diff --git a/DEPS b/DEPS
index ac825fd..8425162 100644
--- a/DEPS
+++ b/DEPS
@@ -121,11 +121,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '673a048b209cba89d4be8e6b8ad7e8a4195fb3cd',
+  'skia_revision': 'd426dd0dd92d3bd99ed96bb7db9f5c7956e2692c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'b8e7365f2467cd4aed7c27f5bdcdfe60c562d96b',
+  'v8_revision': 'e569d8487b3785007945b50e2c5da89a10ca3dd0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -133,7 +133,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': 'fa7ca18f44ed006897067c762b6bacb61d60716a',
+  'angle_revision': 'a7429204afcd957fef29facf44acf06d05cf284e',
   # 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.
@@ -141,11 +141,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'd9e364cff12d0477f5ea924ff7d24fa7e6902e31',
+  'swiftshader_revision': 'ddcbdc51f2aa9767f1f8fc9508e1cb2c14fde107',
   # 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': '31d9a3c0fa79f8561ff1e75116081ab9b051f278',
+  'pdfium_revision': 'f8940afa9d5f0810481a374a5282dfa4c774eb08',
   # 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.
@@ -181,7 +181,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': '432254732785aeba19c43a04c3afe3b2d25bac6c',
+  'catapult_revision': '36e00d45b42c2b88a7fe2ec3e0ef132edb4fc25b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -690,7 +690,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '0b9145e4e1c34980fb3d852824b9c92bf0ca41b6',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8bcc373a271eaea3caf50d85d6d2c4a734c06935',
       'condition': 'checkout_linux',
   },
 
@@ -1047,7 +1047,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '6159b02fa9df4b353b8c5e2db6973d9960d8b9d3',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '64ac720366ce8e92db6528bf4c4ba310a7b1b773',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1251,7 +1251,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@56eebbc3f6932d941a511156edae307ae21e7f3a',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8adced44d39b7287ab7e5d368864964fdc382311',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_gl_surface.cc b/android_webview/browser/aw_gl_surface.cc
index df79dd7..6ed2a73 100644
--- a/android_webview/browser/aw_gl_surface.cc
+++ b/android_webview/browser/aw_gl_surface.cc
@@ -23,7 +23,7 @@
   return ScopedAppGLStateRestore::Current()->framebuffer_binding_ext();
 }
 
-gfx::SwapResult AwGLSurface::SwapBuffers(const PresentationCallback& callback) {
+gfx::SwapResult AwGLSurface::SwapBuffers(PresentationCallback callback) {
   // TODO(penghuang): Provide presentation feedback. https://crbug.com/776877
   return gfx::SwapResult::SWAP_ACK;
 }
diff --git a/android_webview/browser/aw_gl_surface.h b/android_webview/browser/aw_gl_surface.h
index 1e16703..37ac0ae0 100644
--- a/android_webview/browser/aw_gl_surface.h
+++ b/android_webview/browser/aw_gl_surface.h
@@ -21,7 +21,7 @@
   void Destroy() override;
   bool IsOffscreen() override;
   unsigned int GetBackingFramebufferObject() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::Size GetSize() override;
   void* GetHandle() override;
   void* GetDisplay() override;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java
index 3057d796..6f4f333 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTest.java
@@ -36,28 +36,35 @@
     public void
     testModeBrowser() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(
-                shim.runTestForMode("browser", false, "native-include-thread-names", false, false));
+        Assert.assertTrue(shim.runTestForMode(
+                "browser", false, "native-include-thread-names", true, false, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudo() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", false, false));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudoSampleEverything() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true, true));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudoSamplePartial() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true, false));
+    }
+
+    @Test
+    @MediumTest
+    public void testModeBrowserDynamicPseudoSamplePartialNonStreaming() throws Exception {
+        HeapProfilingTestShim shim = new HeapProfilingTestShim();
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", false, true, false));
     }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTestShim.java b/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTestShim.java
index 7403f6b5..6a3f052 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTestShim.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/HeapProfilingTestShim.java
@@ -24,9 +24,9 @@
      *  rather than native stacks.
      */
     public boolean runTestForMode(String mode, boolean dynamicallyStartProfiling, String stackMode,
-            boolean shouldSample, boolean sampleEverything) {
+            boolean streamSamples, boolean shouldSample, boolean sampleEverything) {
         return nativeRunTestForMode(mNativeHeapProfilingTestShim, mode, dynamicallyStartProfiling,
-                stackMode, shouldSample, sampleEverything);
+                stackMode, streamSamples, shouldSample, sampleEverything);
     }
 
     /**
@@ -44,6 +44,6 @@
     private native long nativeInit();
     private native void nativeDestroy(long nativeHeapProfilingTestShim);
     private native boolean nativeRunTestForMode(long nativeHeapProfilingTestShim, String mode,
-            boolean dynamicallyStartProfiling, String stackMode, boolean shouldSample,
-            boolean sampleEverything);
+            boolean dynamicallyStartProfiling, String stackMode, boolean streamSamples,
+            boolean shouldSample, boolean sampleEverything);
 }
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 95017f6..17631d33 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1038,8 +1038,6 @@
     "wm/gestures/overview_gesture_handler.h",
     "wm/immersive_context_ash.cc",
     "wm/immersive_context_ash.h",
-    "wm/immersive_gesture_drag_handler.cc",
-    "wm/immersive_gesture_drag_handler.h",
     "wm/lock_action_handler_layout_manager.cc",
     "wm/lock_action_handler_layout_manager.h",
     "wm/lock_layout_manager.cc",
@@ -1137,16 +1135,15 @@
     "wm/tablet_mode/internal_input_devices_event_blocker.h",
     "wm/tablet_mode/scoped_skip_user_session_blocked_check.cc",
     "wm/tablet_mode/scoped_skip_user_session_blocked_check.h",
-    "wm/tablet_mode/tablet_mode_app_window_drag_controller.cc",
     "wm/tablet_mode/tablet_mode_backdrop_delegate_impl.cc",
     "wm/tablet_mode/tablet_mode_backdrop_delegate_impl.h",
-    "wm/tablet_mode/tablet_mode_browser_window_drag_controller.cc",
-    "wm/tablet_mode/tablet_mode_browser_window_drag_controller.h",
     "wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc",
     "wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h",
     "wm/tablet_mode/tablet_mode_controller.cc",
     "wm/tablet_mode/tablet_mode_event_handler.cc",
     "wm/tablet_mode/tablet_mode_event_handler.h",
+    "wm/tablet_mode/tablet_mode_window_drag_controller.cc",
+    "wm/tablet_mode/tablet_mode_window_drag_controller.h",
     "wm/tablet_mode/tablet_mode_window_drag_delegate.cc",
     "wm/tablet_mode/tablet_mode_window_drag_delegate.h",
     "wm/tablet_mode/tablet_mode_window_manager.cc",
@@ -1768,7 +1765,6 @@
     "wm/fullscreen_window_finder_unittest.cc",
     "wm/gestures/overview_gesture_handler_unittest.cc",
     "wm/immersive_fullscreen_controller_unittest.cc",
-    "wm/immersive_gesture_drag_handler_unittest.cc",
     "wm/lock_action_handler_layout_manager_unittest.cc",
     "wm/lock_layout_manager_unittest.cc",
     "wm/lock_state_controller_unittest.cc",
@@ -1813,6 +1809,7 @@
     "wm/window_preview_view_unittest.cc",
     "wm/window_state_unittest.cc",
     "wm/window_util_unittest.cc",
+    "wm/wm_toplevel_window_event_handler_unittest.cc",
     "wm/workspace/magnetism_matcher_unittest.cc",
     "wm/workspace/multi_window_resize_controller_unittest.cc",
     "wm/workspace/workspace_event_handler_unittest.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index c16bd1e..af650212 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -816,7 +816,7 @@
         Disconnected
       </message>
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED_A11Y" desc="The message used by accessibility for telling that currently the device is not connected to a network.">
-        Not connected to netowrk
+        Not connected to network
       </message>
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING_TOOLTIP" desc="The tooltip text used when network is connecting.">
         Connecting to <ph name="NETWORK_NAME">$1<ex>public wifi</ex></ph>
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
index 6970c32f..28439f1 100644
--- a/ash/drag_drop/drag_drop_controller.cc
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -376,12 +376,20 @@
     case ui::ET_SCROLL_FLING_START:
       Drop(translated_target, *translated_event.get());
       break;
+    case ui::ET_GESTURE_END:
+      // This case occurs when IsUsingWindowService() is true and the user
+      // presses, pauses, and releases a touch without any movement between.
+      // That gesture should be interpreted as a long tap and show a menu, etc.
+      // Classic Ash handles this scenario below via ET_GESTURE_LONG_TAP, while
+      // Mash handles it in DragDropControllerMus::OnPerformDragDropCompleted.
+      DoDragCancel(kTouchCancelAnimationDuration);
+      break;
     case ui::ET_GESTURE_LONG_TAP:
       // Ideally we would want to just forward this long tap event to the
       // |drag_source_window_|. However, webkit does not accept events while a
       // drag drop is still in progress. The drag drop ends only when the nested
       // message loop ends. Due to this stupidity, we have to defer forwarding
-      // the long tap.
+      // the long tap. This only occurs when IsUsingWindowService() is false.
       pending_long_tap_.reset(new ui::GestureEvent(
           *event,
           static_cast<aura::Window*>(drag_drop_tracker_->capture_window()),
diff --git a/ash/public/cpp/immersive/immersive_fullscreen_controller.cc b/ash/public/cpp/immersive/immersive_fullscreen_controller.cc
index bc13d70c..2a91a79 100644
--- a/ash/public/cpp/immersive/immersive_fullscreen_controller.cc
+++ b/ash/public/cpp/immersive/immersive_fullscreen_controller.cc
@@ -26,8 +26,14 @@
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
+DEFINE_UI_CLASS_PROPERTY_TYPE(ash::ImmersiveFullscreenController*);
+
 namespace ash {
 
+DEFINE_UI_CLASS_PROPERTY_KEY(ImmersiveFullscreenController*,
+                             kImmersiveFullscreenControllerKey,
+                             nullptr);
+
 namespace {
 
 // A window targeter installed on a Widget's window when it's in immersive mode.
@@ -110,6 +116,15 @@
   top_container_ = top_container;
   widget_ = widget;
 
+  // A widget can have more than one ImmersiveFullscreenController
+  // (WideFrameView does this), so this key only tracks the first
+  // ImmersiveFullscreenController.
+  if (nullptr == widget->GetNativeWindow()->GetProperty(
+                     kImmersiveFullscreenControllerKey)) {
+    widget->GetNativeWindow()->SetProperty(kImmersiveFullscreenControllerKey,
+                                           this);
+  }
+
   EnableWindowObservers(true);
 }
 
@@ -272,6 +287,13 @@
     widget->GetNativeWindow()->SetProperty(kImmersiveIsActive, enabled);
 }
 
+// static
+ImmersiveFullscreenController* ImmersiveFullscreenController::GetForTest(
+    views::Widget* widget) {
+  return widget->GetNativeWindow()->GetProperty(
+      kImmersiveFullscreenControllerKey);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // private:
 
diff --git a/ash/public/cpp/immersive/immersive_fullscreen_controller.h b/ash/public/cpp/immersive/immersive_fullscreen_controller.h
index 312f97f..78282dc 100644
--- a/ash/public/cpp/immersive/immersive_fullscreen_controller.h
+++ b/ash/public/cpp/immersive/immersive_fullscreen_controller.h
@@ -137,6 +137,8 @@
 
   static void EnableForWidget(views::Widget* widget, bool enabled);
 
+  static ImmersiveFullscreenController* GetForTest(views::Widget* widget);
+
  private:
   friend class ImmersiveFullscreenControllerTest;
   friend class ImmersiveFullscreenControllerTestApi;
diff --git a/ash/wm/immersive_fullscreen_controller_unittest.cc b/ash/wm/immersive_fullscreen_controller_unittest.cc
index 91a1173..66e68ae 100644
--- a/ash/wm/immersive_fullscreen_controller_unittest.cc
+++ b/ash/wm/immersive_fullscreen_controller_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
 
+#include "ash/frame/header_view.h"
+#include "ash/frame/non_client_frame_view_ash.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
@@ -117,6 +119,10 @@
   bool CanResize() const override { return true; }
   bool CanMaximize() const override { return true; }
   bool CanActivate() const override { return true; }
+  views::NonClientFrameView* CreateNonClientFrameView(
+      views::Widget* widget) override {
+    return new NonClientFrameViewAsh(widget);
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate);
@@ -130,36 +136,42 @@
     MODALITY_GESTURE_SCROLL
   };
 
-  ImmersiveFullscreenControllerTest()
-      : widget_(nullptr), top_container_(nullptr), content_view_(nullptr) {}
+  ImmersiveFullscreenControllerTest() = default;
   ~ImmersiveFullscreenControllerTest() override = default;
 
-  ImmersiveFullscreenController* controller() { return controller_.get(); }
+  ImmersiveFullscreenController* controller() {
+    return ImmersiveFullscreenController::GetForTest(widget());
+  }
 
   views::NativeViewHost* content_view() { return content_view_; }
 
-  views::View* top_container() { return top_container_; }
+  views::View* top_container() {
+    return NonClientFrameViewAsh::Get(window())->GetHeaderView();
+  }
 
   views::Widget* widget() { return widget_; }
 
   aura::Window* window() { return widget_->GetNativeWindow(); }
 
-  MockImmersiveFullscreenControllerDelegate* delegate() {
-    return delegate_.get();
+  HeaderView* immersive_delegate() {
+    return NonClientFrameViewAsh::Get(window())->GetHeaderView();
   }
 
   // Access to private data from the controller.
-  bool top_edge_hover_timer_running() const {
-    return controller_->top_edge_hover_timer_.IsRunning();
+  bool top_edge_hover_timer_running() {
+    return controller()->top_edge_hover_timer_.IsRunning();
   }
-  int mouse_x_when_hit_top() const {
-    return controller_->mouse_x_when_hit_top_in_screen_;
+  int mouse_x_when_hit_top() {
+    return controller()->mouse_x_when_hit_top_in_screen_;
   }
 
   // AshTestBase:
   void SetUp() override {
     AshTestBase::SetUp();
 
+    test_api_animation_disabler_ = std::make_unique<
+        ImmersiveFullscreenControllerTestApi::GlobalAnimationDisabler>();
+
     widget_ = new views::Widget();
     views::Widget::InitParams params;
     params.delegate = new TestWidgetDelegate();
@@ -173,20 +185,9 @@
     content_view_->SetBounds(0, 0, window_size.width(), window_size.height());
     widget_->GetContentsView()->AddChildView(content_view_);
 
-    top_container_ = new views::View();
-    top_container_->SetBounds(0, 0, window_size.width(), 100);
-    top_container_->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
-    widget_->GetContentsView()->AddChildView(top_container_);
-
-    delegate_ = std::make_unique<MockImmersiveFullscreenControllerDelegate>(
-        top_container_);
-    controller_ = std::make_unique<ImmersiveFullscreenController>(
-        Shell::Get()->immersive_context());
-    controller_->Init(delegate_.get(), widget_, top_container_);
-    ImmersiveFullscreenControllerTestApi(controller_.get()).SetupForTest();
-
-    // The mouse is moved so that it is not over |top_container_| by
-    // AshTestBase.
+    test_api_ =
+        std::make_unique<ImmersiveFullscreenControllerTestApi>(controller());
+    test_api_->SetupForTest();
   }
 
   // Enables / disables immersive fullscreen.
@@ -211,14 +212,14 @@
   // SetHovered(true) moves the mouse over the |top_container_| but does not
   // move it to the top of the screen so will not initiate a reveal.
   void SetHovered(bool is_mouse_hovered) {
-    MoveMouse(0, is_mouse_hovered ? 10 : top_container_->height() + 100);
+    MoveMouse(0, is_mouse_hovered ? 10 : top_container()->height() + 100);
   }
 
   // Move the mouse to the given coordinates. The coordinates should be in
   // |top_container_| coordinates.
   void MoveMouse(int x, int y) {
     gfx::Point screen_position(x, y);
-    views::View::ConvertPointToScreen(top_container_, &screen_position);
+    views::View::ConvertPointToScreen(top_container(), &screen_position);
     GetEventGenerator()->MoveMouseTo(screen_position.x(), screen_position.y());
 
     // If the top edge timer started running as a result of the mouse move, run
@@ -243,8 +244,9 @@
  private:
   // Attempt to change the revealed state to |revealed| via |modality|.
   void AttemptRevealStateChange(bool revealed, Modality modality) {
-    // Compute the event position in |top_container_| coordinates.
-    gfx::Point event_position(0, revealed ? 0 : top_container_->height() + 100);
+    // Compute the event position in |top_container()| coordinates.
+    gfx::Point event_position(0,
+                              revealed ? 0 : top_container()->height() + 100);
     switch (modality) {
       case MODALITY_MOUSE: {
         MoveMouse(event_position.x(), event_position.y());
@@ -252,7 +254,7 @@
       }
       case MODALITY_GESTURE_TAP: {
         gfx::Point screen_position = event_position;
-        views::View::ConvertPointToScreen(top_container_, &screen_position);
+        views::View::ConvertPointToScreen(top_container(), &screen_position);
         ui::test::EventGenerator* event_generator = GetEventGenerator();
         event_generator->MoveTouch(event_position);
         event_generator->PressTouch();
@@ -260,11 +262,11 @@
         break;
       }
       case MODALITY_GESTURE_SCROLL: {
-        gfx::Point start(0, revealed ? 0 : top_container_->height() - 2);
+        gfx::Point start(0, revealed ? 0 : 2);
         gfx::Vector2d scroll_delta(0, 40);
         gfx::Point end = revealed ? start + scroll_delta : start - scroll_delta;
-        views::View::ConvertPointToScreen(top_container_, &start);
-        views::View::ConvertPointToScreen(top_container_, &end);
+        views::View::ConvertPointToScreen(top_container(), &start);
+        views::View::ConvertPointToScreen(top_container(), &end);
         ui::test::EventGenerator* event_generator = GetEventGenerator();
         event_generator->GestureScrollSequence(
             start, end, base::TimeDelta::FromMilliseconds(30), 1);
@@ -273,11 +275,12 @@
     }
   }
 
-  std::unique_ptr<ImmersiveFullscreenController> controller_;
-  std::unique_ptr<MockImmersiveFullscreenControllerDelegate> delegate_;
-  views::Widget* widget_;                // Owned by the native widget.
-  views::View* top_container_;           // Owned by |widget_|'s root-view.
-  views::NativeViewHost* content_view_;  // Owned by |widget_|'s root-view.
+  std::unique_ptr<ImmersiveFullscreenControllerTestApi::GlobalAnimationDisabler>
+      test_api_animation_disabler_;
+  views::Widget* widget_ = nullptr;  // Owned by the native widget.
+  views::NativeViewHost* content_view_ =
+      nullptr;  // Owned by |widget_|'s root-view.
+  std::unique_ptr<ImmersiveFullscreenControllerTestApi> test_api_;
 
   base::test::ScopedFeatureList scoped_feature_list_;
 
@@ -287,34 +290,38 @@
 // Test the initial state and that the delegate gets notified of the
 // top-of-window views getting hidden and revealed.
 TEST_F(ImmersiveFullscreenControllerTest, Delegate) {
+  SetWindowShowState(ui::SHOW_STATE_MAXIMIZED);
+
   // Initial state.
   EXPECT_FALSE(controller()->IsEnabled());
   EXPECT_FALSE(controller()->IsRevealed());
-  EXPECT_FALSE(delegate()->is_enabled());
+  EXPECT_FALSE(immersive_delegate()->in_immersive_mode());
 
   // Enabling initially hides the top views.
   SetEnabled(true);
   EXPECT_TRUE(controller()->IsEnabled());
   EXPECT_FALSE(controller()->IsRevealed());
-  EXPECT_TRUE(delegate()->is_enabled());
-  EXPECT_EQ(0, delegate()->visible_fraction());
+  EXPECT_TRUE(immersive_delegate()->in_immersive_mode());
+  EXPECT_FALSE(immersive_delegate()->is_revealed());
 
   // Revealing shows the top views.
   AttemptReveal(MODALITY_MOUSE);
   EXPECT_TRUE(controller()->IsEnabled());
   EXPECT_TRUE(controller()->IsRevealed());
-  EXPECT_TRUE(delegate()->is_enabled());
-  EXPECT_EQ(1, delegate()->visible_fraction());
+  EXPECT_TRUE(immersive_delegate()->in_immersive_mode());
+  EXPECT_TRUE(immersive_delegate()->is_revealed());
 
   // Disabling ends the immersive reveal.
   SetEnabled(false);
   EXPECT_FALSE(controller()->IsEnabled());
   EXPECT_FALSE(controller()->IsRevealed());
-  EXPECT_FALSE(delegate()->is_enabled());
+  EXPECT_FALSE(immersive_delegate()->in_immersive_mode());
 }
 
 // GetRevealedLock() specific tests.
 TEST_F(ImmersiveFullscreenControllerTest, RevealedLock) {
+  SetWindowShowState(ui::SHOW_STATE_MAXIMIZED);
+
   std::unique_ptr<ImmersiveRevealedLock> lock1;
   std::unique_ptr<ImmersiveRevealedLock> lock2;
 
@@ -354,6 +361,10 @@
       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
   EXPECT_TRUE(controller()->IsRevealed());
 
+  // Move the mouse below the top container bounds so the hover doesn't make the
+  // reveal persist.
+  MoveMouse(0, top_container()->GetBoundsInScreen().bottom() + 10);
+
   // 3) Test that the top-of-window views are only hidden when all of the locks
   // are released.
   lock2.reset(controller()->GetRevealedLock(
@@ -690,18 +701,17 @@
 // Tests the top-of-window views for maximized/full-screened/snapped windows in
 // tablet mode.
 TEST_F(ImmersiveFullscreenControllerTest, WindowsInTabletMode) {
-  SetWindowShowState(ui::SHOW_STATE_MAXIMIZED);
   EnableTabletMode(true);
   SetEnabled(true);
   EXPECT_TRUE(controller()->IsEnabled());
   EXPECT_FALSE(controller()->IsRevealed());
 
   // Top-of-window views will not be revealed through gesture scroll for
-  // maximized window in tablet mode.
+  // fullscreen window in tablet mode. (Instead, the window is dragged.)
   AttemptReveal(MODALITY_GESTURE_SCROLL);
   EXPECT_FALSE(controller()->IsRevealed());
 
-  // Top-of-window views will be revealed for maximized window not in tablet
+  // Top-of-window views will be revealed for fullscreen windows not in tablet
   // mode.
   EnableTabletMode(false);
   AttemptReveal(MODALITY_GESTURE_SCROLL);
@@ -826,6 +836,7 @@
 // Check that the window state gets properly marked for immersive fullscreen.
 TEST_F(ImmersiveFullscreenControllerTest, WindowStateImmersiveFullscreen) {
   ash::wm::WindowState* window_state = ash::wm::GetWindowState(window());
+  SetWindowShowState(ui::SHOW_STATE_NORMAL);
 
   EXPECT_FALSE(window_state->IsInImmersiveFullscreen());
   SetEnabled(true);
@@ -869,17 +880,18 @@
   EXPECT_FALSE(controller()->IsRevealed());
 
   // 2) Test that focusing |unrelated_view| hides the top-of-window views.
-  // Note: In this test we can cheat and trigger a reveal via focus because
-  // the top container does not hide when the top-of-window views are not
-  // revealed.
+  AttemptReveal(MODALITY_MOUSE);
   child_view->RequestFocus();
+  SetHovered(false);
   EXPECT_TRUE(controller()->IsRevealed());
   unrelated_view->RequestFocus();
   EXPECT_FALSE(controller()->IsRevealed());
 
   // 3) Test that a loss of focus of |child_view| to |unrelated_view|
   // while immersive mode is disabled is properly registered.
+  AttemptReveal(MODALITY_MOUSE);
   child_view->RequestFocus();
+  SetHovered(false);
   EXPECT_TRUE(controller()->IsRevealed());
   SetEnabled(false);
   EXPECT_FALSE(controller()->IsRevealed());
@@ -889,7 +901,9 @@
 
   // Repeat test but with a revealed lock acquired when immersive mode is
   // disabled because the code path is different.
+  AttemptReveal(MODALITY_MOUSE);
   child_view->RequestFocus();
+  SetHovered(false);
   EXPECT_TRUE(controller()->IsRevealed());
   SetEnabled(false);
   std::unique_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock(
diff --git a/ash/wm/immersive_gesture_drag_handler.cc b/ash/wm/immersive_gesture_drag_handler.cc
deleted file mode 100644
index 9b73a19..0000000
--- a/ash/wm/immersive_gesture_drag_handler.cc
+++ /dev/null
@@ -1,131 +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/immersive_gesture_drag_handler.h"
-
-#include "ash/public/cpp/app_types.h"
-#include "ash/public/cpp/ash_features.h"
-#include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
-#include "ash/shell.h"
-#include "ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h"
-#include "ash/wm/tablet_mode/tablet_mode_controller.h"
-#include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h"
-#include "ash/wm/window_state.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/window.h"
-#include "ui/display/screen.h"
-#include "ui/events/event.h"
-#include "ui/views/widget/widget.h"
-
-namespace ash {
-namespace {
-
-// How many pixels are reserved for gesture events to start dragging the app
-// window from the top of the screen in tablet mode.
-constexpr int kDragStartTopEdgeInset = 8;
-
-// Check whether we should start gesture dragging app window according to the
-// given ET_GETURE_SCROLL_BEGIN type |event|.
-bool CanBeginGestureDrag(ui::GestureEvent* event) {
-  if (event->details().scroll_y_hint() < 0)
-    return false;
-
-  const gfx::Point location_in_screen =
-      event->target()->GetScreenLocation(*event);
-  const gfx::Rect work_area_bounds =
-      display::Screen::GetScreen()
-          ->GetDisplayNearestWindow(static_cast<aura::Window*>(event->target()))
-          .work_area();
-
-  gfx::Rect hit_bounds_in_screen(work_area_bounds);
-  hit_bounds_in_screen.set_height(kDragStartTopEdgeInset);
-  if (hit_bounds_in_screen.Contains(location_in_screen))
-    return true;
-
-  // There may be a bezel sensor off screen logically above
-  // |hit_bounds_in_screen|. Handles the ET_GESTURE_SCROLL_BEGIN event
-  // triggerd in the bezel area too.
-  return location_in_screen.y() < hit_bounds_in_screen.y() &&
-         location_in_screen.x() >= hit_bounds_in_screen.x() &&
-         location_in_screen.x() < hit_bounds_in_screen.right();
-}
-
-}  // namespace
-
-ImmersiveGestureDragHandler::ImmersiveGestureDragHandler(aura::Window* window)
-    : window_(window) {
-  Shell::Get()->AddPreTargetHandler(this);
-}
-
-ImmersiveGestureDragHandler::~ImmersiveGestureDragHandler() {
-  Shell::Get()->RemovePreTargetHandler(this);
-}
-
-void ImmersiveGestureDragHandler::OnGestureEvent(ui::GestureEvent* event) {
-  if (CanDrag(event)) {
-    DCHECK(tablet_mode_app_window_drag_controller_);
-    if (tablet_mode_app_window_drag_controller_->DragWindowFromTop(event))
-      event->SetHandled();
-  } else if (tablet_mode_app_window_drag_controller_ &&
-             tablet_mode_app_window_drag_controller_->drag_delegate()
-                 ->dragged_window()) {
-    // Set the event as handled during app window drag if CanDrag(event) is
-    // false. Then the gesture events that triggered outside of the dragged
-    // window will not be proceeded to break the drag. Note, browser window
-    // doesn't use TabletModeWindowAppWindowDragController but WindowResizer to
-    // do window drag. It has its own logic to deal with the case.
-    event->SetHandled();
-  }
-}
-
-bool ImmersiveGestureDragHandler::CanDrag(ui::GestureEvent* event) {
-  views::Widget* widget = views::Widget::GetTopLevelWidgetForNativeView(
-      static_cast<aura::Window*>(event->target()));
-  if (!widget)
-    return false;
-
-  if (widget->GetNativeWindow() != window_)
-    return false;
-
-  // Maximized, fullscreened and snapped windows in tablet mode are allowed to
-  // be dragged.
-  wm::WindowState* window_state = wm::GetWindowState(window_);
-  if (!window_state ||
-      (!window_state->IsMaximized() && !window_state->IsFullscreen() &&
-       !window_state->IsSnapped()) ||
-      !Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled()) {
-    return false;
-  }
-
-  // Fullscreen browser windows are not draggable. Dragging from top should show
-  // the frame.
-  if (window_state->IsFullscreen() &&
-      window_->GetProperty(aura::client::kAppType) ==
-          static_cast<int>(AppType::BROWSER)) {
-    return false;
-  }
-
-  // Start to drag window until ET_GESTURE_SCROLL_BEGIN event happened.
-  if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
-    if (!CanBeginGestureDrag(event))
-      return false;
-    tablet_mode_app_window_drag_controller_ =
-        std::make_unique<TabletModeAppWindowDragController>();
-    return true;
-  }
-
-  // Should not start dragging window until
-  // |tablet_mode_app_window_drag_controller_| have been created.
-  if (event->type() != ui::ET_GESTURE_SCROLL_BEGIN &&
-      !tablet_mode_app_window_drag_controller_) {
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace ash
diff --git a/ash/wm/immersive_gesture_drag_handler.h b/ash/wm/immersive_gesture_drag_handler.h
deleted file mode 100644
index 07c19ee..0000000
--- a/ash/wm/immersive_gesture_drag_handler.h
+++ /dev/null
@@ -1,46 +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_IMMERSIVE_GESTURE_DRAG_HANDLER_H_
-#define ASH_WM_IMMERSIVE_GESTURE_DRAG_HANDLER_H_
-
-#include <memory>
-
-#include "ash/ash_export.h"
-#include "ui/events/event_handler.h"
-
-namespace aura {
-class Window;
-}
-
-namespace ash {
-
-class TabletModeAppWindowDragController;
-
-// ImmersiveGestureHandler is responsible for calling
-// TabletAppModeWindowDragController::DragWindowFromTop() to drag the window
-// from the top if CanDrag is true when a gesture is received.
-class ASH_EXPORT ImmersiveGestureDragHandler : public ui::EventHandler {
- public:
-  explicit ImmersiveGestureDragHandler(aura::Window* window);
-  ~ImmersiveGestureDragHandler() override;
-
-  // ui::EventHandler:
-  void OnGestureEvent(ui::GestureEvent* event) override;
-
- private:
-  // Returns true if the target of |event| can be dragged.
-  bool CanDrag(ui::GestureEvent* event);
-
-  std::unique_ptr<TabletModeAppWindowDragController>
-      tablet_mode_app_window_drag_controller_;
-
-  aura::Window* window_;
-
-  DISALLOW_COPY_AND_ASSIGN(ImmersiveGestureDragHandler);
-};
-
-}  // namespace ash
-
-#endif  // ASH_WM_IMMERSIVE_GESTURE_DRAG_HANDLER_H_
diff --git a/ash/wm/immersive_gesture_drag_handler_unittest.cc b/ash/wm/immersive_gesture_drag_handler_unittest.cc
deleted file mode 100644
index b8b39d3b..0000000
--- a/ash/wm/immersive_gesture_drag_handler_unittest.cc
+++ /dev/null
@@ -1,127 +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 "ash/wm/immersive_gesture_drag_handler.h"
-
-#include "ash/public/cpp/app_types.h"
-#include "ash/shell.h"
-#include "ash/system/overview/overview_button_tray.h"
-#include "ash/system/status_area_widget.h"
-#include "ash/system/status_area_widget_test_helper.h"
-#include "ash/test/ash_test_base.h"
-#include "ash/wm/overview/overview_controller.h"
-#include "ash/wm/overview/overview_grid.h"
-#include "ash/wm/overview/overview_item.h"
-#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
-#include "ash/wm/window_state.h"
-#include "base/time/time.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/events/test/event_generator.h"
-
-namespace ash {
-
-class ImmersiveGestureDragHandlerTest : public AshTestBase {
- public:
-  ImmersiveGestureDragHandlerTest() = default;
-  ~ImmersiveGestureDragHandlerTest() override = default;
-
-  void SetUp() override {
-    AshTestBase::SetUp();
-    TabletModeControllerTestApi().EnterTabletMode();
-
-    dragged_window_ = CreateTestWindow();
-    none_dragged_window_ = CreateTestWindow();
-    dragged_window_->SetProperty(aura::client::kAppType,
-                                 static_cast<int>(AppType::CHROME_APP));
-    handler_ =
-        std::make_unique<ImmersiveGestureDragHandler>(dragged_window_.get());
-  }
-
-  void TearDown() override {
-    handler_.reset();
-    none_dragged_window_.reset();
-    dragged_window_.reset();
-    AshTestBase::TearDown();
-  }
-
- protected:
-  // Send gesture event with |type| to |handler_|.
-  void SendGestureEvent(const gfx::Point& position,
-                        int scroll_x,
-                        int scroll_y,
-                        ui::EventType type) {
-    ui::GestureEvent event = ui::GestureEvent(
-        position.x(), position.y(), ui::EF_NONE, base::TimeTicks::Now(),
-        ui::GestureEventDetails(type, scroll_x, scroll_y));
-    ui::Event::DispatcherApi(&event).set_target(dragged_window_.get());
-    handler_->OnGestureEvent(&event);
-  }
-
-  std::unique_ptr<aura::Window> dragged_window_;
-  std::unique_ptr<aura::Window> none_dragged_window_;
-  std::unique_ptr<ImmersiveGestureDragHandler> handler_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ImmersiveGestureDragHandlerTest);
-};
-
-// Tests that tap the window in overview grid during window drag should not end
-// the overview mode and the window should still be kept in overview grid.
-TEST_F(ImmersiveGestureDragHandlerTest,
-       TapWindowInOverviewGridDuringWindowDrag) {
-  ASSERT_TRUE(TabletModeControllerTestApi().IsTabletModeStarted());
-
-  SendGestureEvent(gfx::Point(0, 0), 0, 5, ui::ET_GESTURE_SCROLL_BEGIN);
-  // Drag the window to the right corner to avoid overlap with
-  // |none_dragged_window_| in overview grid.
-  SendGestureEvent(gfx::Point(700, 500), 700, 500,
-                   ui::ET_GESTURE_SCROLL_UPDATE);
-  EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->is_dragged());
-
-  EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting());
-  OverviewSession* overview_session =
-      Shell::Get()->overview_controller()->overview_session();
-  EXPECT_TRUE(overview_session->IsWindowInOverview(none_dragged_window_.get()));
-
-  OverviewGrid* current_grid = overview_session->GetGridWithRootWindow(
-      none_dragged_window_->GetRootWindow());
-  OverviewItem* item =
-      current_grid->GetOverviewItemContaining(none_dragged_window_.get());
-  GetEventGenerator()->GestureTapAt(item->GetTransformedBounds().CenterPoint());
-
-  // Overview mode is still active and |none_dragged_window_| is still in
-  // overview grid after tried to tap it in overview grid.
-  EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_TRUE(overview_session->IsWindowInOverview(none_dragged_window_.get()));
-}
-
-// Tests that tap the overview button during window drag should not end overview
-// mode.
-TEST_F(ImmersiveGestureDragHandlerTest, TapOverviewButtonDuringWindowDrag) {
-  ASSERT_TRUE(TabletModeControllerTestApi().IsTabletModeStarted());
-
-  SendGestureEvent(gfx::Point(0, 0), 0, 5, ui::ET_GESTURE_SCROLL_BEGIN);
-  // Drag the window to the right corner to avoid overlap with
-  // |none_dragged_window_| in overview grid.
-  SendGestureEvent(gfx::Point(700, 500), 700, 500,
-                   ui::ET_GESTURE_SCROLL_UPDATE);
-  EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->is_dragged());
-  EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting());
-  OverviewSession* overview_session =
-      Shell::Get()->overview_controller()->overview_session();
-
-  EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting());
-  OverviewButtonTray* overview_button_tray =
-      StatusAreaWidgetTestHelper::GetStatusAreaWidget()->overview_button_tray();
-  ASSERT_TRUE(overview_button_tray->visible());
-  GetEventGenerator()->GestureTapAt(
-      overview_button_tray->GetBoundsInScreen().CenterPoint());
-
-  // Overview mode is still active and |none_dragged_window_| is still in
-  // overview grid after tap the overview button.
-  EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_TRUE(overview_session->IsWindowInOverview(none_dragged_window_.get()));
-}
-
-}  // namespace ash
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 645f97a..f806336 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -31,8 +31,10 @@
 #include "ash/wm/overview/overview_window_drag_controller.h"
 #include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/splitview/split_view_divider.h"
-#include "ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h"
+#include "ash/wm/splitview/split_view_utils.h"
+#include "ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_window_drag_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_event.h"
@@ -2499,8 +2501,9 @@
   EXPECT_NE(bounds3, item3->target_bounds());
 }
 
-// Tests that overview mode is entered with kWindowDragged mode when an app is
-// dragged from the top of the screen.
+// Tests that overview mode is entered with kWindowDragged mode when a window is
+// dragged from the top of the screen. For the purposes of this test, we use a
+// browser window.
 TEST_F(OverviewSessionTest, DraggingFromTopAnimation) {
   EnterTabletMode();
   std::unique_ptr<views::Widget> widget(CreateTestWidget(
@@ -2508,12 +2511,16 @@
   widget->GetNativeWindow()->SetProperty(aura::client::kTopViewInset, 20);
 
   // Drag from the the top of the app to enter overview.
-  auto drag_controller = std::make_unique<TabletModeAppWindowDragController>();
   ui::GestureEvent event(0, 0, 0, base::TimeTicks(),
                          ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
+  wm::WindowState* window_state = wm::GetWindowState(widget->GetNativeWindow());
+  window_state->CreateDragDetails(event.location(), HTCAPTION,
+                                  ::wm::WINDOW_MOVE_SOURCE_TOUCH);
+  auto drag_controller = std::make_unique<TabletModeWindowDragController>(
+      window_state, std::make_unique<TabletModeBrowserWindowDragDelegate>());
   ui::Event::DispatcherApi dispatch_helper(&event);
   dispatch_helper.set_target(widget->GetNativeWindow());
-  drag_controller->DragWindowFromTop(&event);
+  drag_controller->Drag(event.location(), event.flags());
 
   ASSERT_TRUE(IsSelecting());
   EXPECT_EQ(OverviewSession::EnterExitOverviewType::kWindowDragged,
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index dd662de..c13db53 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -28,9 +28,9 @@
 #include "ash/wm/splitview/split_view_divider.h"
 #include "ash/wm/splitview/split_view_drag_indicators.h"
 #include "ash/wm/splitview/split_view_utils.h"
-#include "ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h"
-#include "ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_window_drag_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h"
 #include "ash/wm/window_resizer.h"
 #include "ash/wm/window_state.h"
@@ -1866,9 +1866,8 @@
     // we can do to simplify the logic and hide impl details.
     real_window_resizer = static_cast<DragWindowResizer*>(resizer)
                               ->next_window_resizer_for_testing();
-    TabletModeBrowserWindowDragController* browser_controller =
-        static_cast<TabletModeBrowserWindowDragController*>(
-            real_window_resizer);
+    TabletModeWindowDragController* browser_controller =
+        static_cast<TabletModeWindowDragController*>(real_window_resizer);
 
     return browser_controller->drag_delegate_for_testing()
         ->split_view_drag_indicators_for_testing()
@@ -3496,20 +3495,14 @@
   ~SplitViewAppDraggingTest() override = default;
 
   // SplitViewControllerTest:
-  void SetUp() override {
-    SplitViewControllerTest::SetUp();
-    controller_ = std::make_unique<TabletModeAppWindowDragController>();
-  }
-
-  // SplitViewControllerTest:
   void TearDown() override {
+    window_.reset();
     controller_.reset();
     SplitViewControllerTest::TearDown();
   }
 
  protected:
-  std::unique_ptr<aura::Window> CreateTestWindowWithWidget(
-      bool can_activate = true) {
+  std::unique_ptr<aura::Window> CreateTestWindowWithWidget(bool can_activate) {
     views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
     params.show_state = ui::SHOW_STATE_MAXIMIZED;
     views::Widget* widget = new views::Widget;
@@ -3523,173 +3516,164 @@
     return base::WrapUnique<aura::Window>(widget->GetNativeView());
   }
 
-  // Sends a gesture scroll sequence to TabletModeAppWindowDragController.
-  void SendGestureEvents(const gfx::Point& start,
-                         float scroll_delta,
-                         aura::Window* window) {
-    base::TimeTicks timestamp = base::TimeTicks::Now();
-    SendScrollStartAndUpdate(start, scroll_delta, timestamp, window);
+  void InitializeWindow(bool can_activate = true) {
+    window_ = CreateTestWindowWithWidget(can_activate);
+  }
 
-    EndScrollSequence(start, scroll_delta, timestamp, window);
+  // Sends a gesture scroll sequence to TabletModeAppWindowDragController.
+  void SendGestureEvents(const gfx::Point& start, float scroll_delta) {
+    base::TimeTicks timestamp = base::TimeTicks::Now();
+    SendScrollStartAndUpdate(start, scroll_delta, timestamp);
+    EndScrollSequence();
   }
 
   void SendScrollStartAndUpdate(const gfx::Point& start,
                                 float scroll_y,
                                 base::TimeTicks& timestamp,
-                                aura::Window* window,
                                 float scroll_x = 0.f) {
-    SendGestureEventToController(
-        start.x(), start.y(), timestamp,
-        ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0), window);
+    wm::WindowState* window_state = wm::GetWindowState(window());
+    window_state->CreateDragDetails(start, HTCAPTION,
+                                    ::wm::WINDOW_MOVE_SOURCE_TOUCH);
+    controller_ = std::make_unique<TabletModeWindowDragController>(
+        window_state, std::make_unique<TabletModeBrowserWindowDragDelegate>());
 
     timestamp += base::TimeDelta::FromMilliseconds(100);
-    SendGestureEventToController(
-        start.x() + scroll_x, start.y() + scroll_y, timestamp,
-        ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, scroll_x,
-                                scroll_y),
-        window);
+    controller_->Drag(start + gfx::Vector2d(scroll_x, scroll_y), 0);
   }
 
-  void EndScrollSequence(const gfx::Point& start,
-                         float scroll_delta,
-                         base::TimeTicks& timestamp,
-                         aura::Window* window,
-                         bool is_fling = false,
-                         float velocity_y = 0.f,
-                         float velocity_x = 0.f) {
+  void EndScrollSequence() {
+    controller_->CompleteDrag();
+    wm::GetWindowState(window())->DeleteDragDetails();
+  }
+
+  void Fling(const gfx::Point& start,
+             float scroll_delta,
+             base::TimeTicks& timestamp,
+             float velocity_y,
+             float velocity_x) {
     timestamp += base::TimeDelta::FromMilliseconds(100);
-    ui::GestureEventDetails details =
-        is_fling ? ui::GestureEventDetails(ui::ET_SCROLL_FLING_START,
-                                           velocity_x, velocity_y)
-                 : ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END);
-    SendGestureEventToController(start.x(), start.y() + scroll_delta, timestamp,
-                                 details, window);
+    ui::GestureEvent event =
+        ui::GestureEvent(start.x(), start.y(), ui::EF_NONE, timestamp,
+                         ui::GestureEventDetails(ui::ET_SCROLL_FLING_START,
+                                                 velocity_x, velocity_y));
+    ui::Event::DispatcherApi(&event).set_target(window());
+    controller_->FlingOrSwipe(&event);
+    wm::GetWindowState(window())->DeleteDragDetails();
   }
 
   IndicatorState GetIndicatorState() {
-    return controller_->drag_delegate()
+    return controller_->drag_delegate_for_testing()
         ->split_view_drag_indicators_for_testing()
         ->current_indicator_state();
   }
 
+  aura::Window* window() { return window_.get(); }
+
+  std::unique_ptr<TabletModeWindowDragController> controller_;
+
+  std::unique_ptr<aura::Window> window_;
+
  private:
-  void SendGestureEventToController(int x,
-                                    int y,
-                                    base::TimeTicks& timestamp,
-                                    const ui::GestureEventDetails& details,
-                                    aura::Window* window) {
-    ui::GestureEvent event =
-        ui::GestureEvent(x, y, ui::EF_NONE, timestamp, details);
-    ui::Event::DispatcherApi(&event).set_target(window);
-    controller_->DragWindowFromTop(&event);
-  }
-
-  std::unique_ptr<TabletModeAppWindowDragController> controller_;
-
   DISALLOW_COPY_AND_ASSIGN(SplitViewAppDraggingTest);
 };
 
 // Tests that drag the window that cannot be snapped from top of the display
 // will not snap the window into splitscreen.
-TEST_F(SplitViewAppDraggingTest, DragNoneActiveMaximizedWindow) {
+TEST_F(SplitViewAppDraggingTest, DragNonActiveMaximizedWindow) {
   UpdateDisplay("800x600");
-  std::unique_ptr<aura::Window> window = CreateTestWindowWithWidget(false);
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
+  InitializeWindow(false);
+  EXPECT_TRUE(wm::GetWindowState(window())->IsMaximized());
   gfx::Rect display_bounds =
       screen_util::GetDisplayWorkAreaBoundsInScreenForDefaultContainer(
-          window.get());
+          window());
   const float long_scroll_delta = display_bounds.height() / 4 + 5;
 
   const gfx::Point start;
   // Drag the window that cannot be snapped long enough, the window will be
   // dropped into overview.
   base::TimeTicks timestamp = base::TimeTicks::Now();
-  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get());
+  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->IsSelecting());
-  EXPECT_FALSE(overview_controller->overview_session()->IsWindowInOverview(
-      window.get()));
-  EndScrollSequence(start, long_scroll_delta, timestamp, window.get());
+  EXPECT_FALSE(
+      overview_controller->overview_session()->IsWindowInOverview(window()));
+  EndScrollSequence();
   EXPECT_TRUE(overview_controller->IsSelecting());
   EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive());
-  EXPECT_TRUE(overview_controller->overview_session()->IsWindowInOverview(
-      window.get()));
+  EXPECT_TRUE(
+      overview_controller->overview_session()->IsWindowInOverview(window()));
 }
 
 // Tests the functionalities that are related to dragging a maximized window
 // into splitscreen.
 TEST_F(SplitViewAppDraggingTest, DragActiveMaximizedWindow) {
   UpdateDisplay("800x600");
-  std::unique_ptr<aura::Window> window = CreateTestWindowWithWidget();
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
+  InitializeWindow();
+  EXPECT_TRUE(wm::GetWindowState(window())->IsMaximized());
   gfx::Rect display_bounds =
       screen_util::GetDisplayWorkAreaBoundsInScreenForDefaultContainer(
-          window.get());
+          window());
 
   // Move the window by a small amount of distance will maximize the window
   // again.
   const gfx::Point start;
-  SendGestureEvents(start, 10, window.get());
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
+  SendGestureEvents(start, 10);
+  EXPECT_TRUE(wm::GetWindowState(window())->IsMaximized());
 
   // Drag the window long enough (pass one fourth of the screen vertical
   // height) to snap the window to splitscreen.
   const float long_scroll_delta = display_bounds.height() / 4 + 5;
   base::TimeTicks timestamp = base::TimeTicks::Now();
-  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get());
+  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->IsSelecting());
-  EXPECT_FALSE(overview_controller->overview_session()->IsWindowInOverview(
-      window.get()));
-  EndScrollSequence(start, long_scroll_delta, timestamp, window.get());
+  EXPECT_FALSE(
+      overview_controller->overview_session()->IsWindowInOverview(window()));
+  EndScrollSequence();
   EXPECT_TRUE(overview_controller->IsSelecting());
   EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive());
-  EXPECT_EQ(split_view_controller()->left_window(), window.get());
+  EXPECT_EQ(split_view_controller()->left_window(), window());
   EXPECT_EQ(split_view_controller()->state(),
             SplitViewController::LEFT_SNAPPED);
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsSnapped());
+  EXPECT_TRUE(wm::GetWindowState(window())->IsSnapped());
 
   // FLING the window with small velocity (smaller than
   // kFlingToOverviewThreshold) will not able to drop the window into overview.
   timestamp = base::TimeTicks::Now();
-  SendScrollStartAndUpdate(start, 10, timestamp, window.get());
+  SendScrollStartAndUpdate(start, 10, timestamp);
   overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->IsSelecting());
-  EndScrollSequence(
-      start, 10, timestamp, window.get(), /*is_fling=*/true,
-      /*velocity_y=*/
-      TabletModeWindowDragDelegate::kFlingToOverviewThreshold - 10.f);
+  Fling(start, 10, timestamp,
+        TabletModeWindowDragDelegate::kFlingToOverviewThreshold - 10.f, 0);
   EXPECT_FALSE(overview_controller->IsSelecting());
 
-  // FLING the window with large veloicty (larger than
+  // FLING the window with large velocity (larger than
   // kFlingToOverviewThreshold) will drop the window into overview.
   timestamp = base::TimeTicks::Now();
-  SendScrollStartAndUpdate(start, 10, timestamp, window.get());
+  SendScrollStartAndUpdate(start, 10, timestamp);
   overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->IsSelecting());
-  EndScrollSequence(
-      start, 10, timestamp, window.get(), /*is_fling=*/true,
-      /*velocity_y=*/
-      TabletModeWindowDragDelegate::kFlingToOverviewThreshold + 10.f);
+  Fling(start, 10, timestamp,
+        TabletModeWindowDragDelegate::kFlingToOverviewThreshold + 10.f, 0);
   EXPECT_TRUE(overview_controller->IsSelecting());
 }
 
 // Tests the shelf visibility when a fullscreened window is being dragged.
 TEST_F(SplitViewAppDraggingTest, ShelfVisibilityIfDraggingFullscreenedWindow) {
   UpdateDisplay("800x600");
-  std::unique_ptr<aura::Window> window = CreateTestWindowWithWidget();
+  InitializeWindow();
   ShelfLayoutManager* shelf_layout_manager =
       AshTestBase::GetPrimaryShelf()->shelf_layout_manager();
   gfx::Rect display_bounds =
       screen_util::GetDisplayWorkAreaBoundsInScreenForDefaultContainer(
-          window.get());
+          window());
 
-  // Shelf will be auto-hidden if the winodw requests to be fullscreened.
-  wm::WindowState* window_state = wm::GetWindowState(window.get());
+  // Shelf will be auto-hidden if the window requests to be fullscreened.
+  wm::WindowState* window_state = wm::GetWindowState(window());
   const wm::WMEvent fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
   window_state->OnWMEvent(&fullscreen_event);
   window_state->SetHideShelfWhenFullscreen(false);
-  window->SetProperty(kImmersiveIsActive, true);
+  window()->SetProperty(kImmersiveIsActive, true);
   shelf_layout_manager->UpdateVisibilityState();
   EXPECT_TRUE(window_state->IsFullscreen());
   EXPECT_FALSE(shelf_layout_manager->IsVisible());
@@ -3697,18 +3681,19 @@
   // Drag the window by a small amount of distance, the window will back to
   // fullscreened, and shelf will be hidden again.
   const gfx::Point start;
-  SendGestureEvents(start, 10, window.get());
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsFullscreen());
+  SendGestureEvents(start, 10);
+  shelf_layout_manager->UpdateVisibilityState();
+  EXPECT_TRUE(window_state->IsFullscreen());
   EXPECT_FALSE(shelf_layout_manager->IsVisible());
 
   // Shelf is visible during dragging.
   base::TimeTicks timestamp = base::TimeTicks::Now();
   const float long_scroll_delta = display_bounds.height() / 4 + 5;
-  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get());
+  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp);
   EXPECT_TRUE(shelf_layout_manager->IsVisible());
-  EndScrollSequence(start, long_scroll_delta, timestamp, window.get());
+  EndScrollSequence();
   EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive());
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsSnapped());
+  EXPECT_TRUE(wm::GetWindowState(window())->IsSnapped());
   EXPECT_TRUE(shelf_layout_manager->IsVisible());
 }
 
@@ -3717,14 +3702,14 @@
   UpdateDisplay("800x600");
   Shelf* shelf = GetPrimaryShelf();
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
-  std::unique_ptr<aura::Window> window = CreateTestWindowWithWidget();
+  InitializeWindow();
   gfx::Rect display_bounds =
       display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
   ShelfLayoutManager* shelf_layout_manager =
       AshTestBase::GetPrimaryShelf()->shelf_layout_manager();
   shelf_layout_manager->LayoutShelf();
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
+  EXPECT_TRUE(wm::GetWindowState(window())->IsMaximized());
 
   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
   shelf_layout_manager->LayoutShelf();
@@ -3734,68 +3719,32 @@
   base::TimeTicks timestamp = base::TimeTicks::Now();
   const gfx::Point start;
   const float long_scroll_delta = display_bounds.height() / 4 + 5;
-  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get());
+  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp);
   EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
   // Shelf should be shown during drag.
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
-  EndScrollSequence(start, long_scroll_delta, timestamp, window.get());
+  EndScrollSequence();
   EXPECT_EQ(split_view_controller()->state(),
             SplitViewController::LEFT_SNAPPED);
   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
   // Shelf should be shown after drag and snapped window should be covered by
   // the auto-hide-shown shelf.
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
-  EXPECT_EQ(split_view_controller()
-                ->GetSnappedWindowBoundsInScreen(window.get(),
-                                                 SplitViewController::LEFT)
-                .height(),
-            display_bounds.height());
-}
-
-// Tests that the app drag will be reverted if the screen is being rotated.
-TEST_F(SplitViewAppDraggingTest, DisplayConfigurationChangeTest) {
-  UpdateDisplay("800x600");
-  int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
-  display::DisplayManager* display_manager = Shell::Get()->display_manager();
-  display::test::ScopedSetInternalDisplayId set_internal(display_manager,
-                                                         display_id);
-  ScreenOrientationControllerTestApi test_api(
-      Shell::Get()->screen_orientation_controller());
-  // Set the screen orientation to LANDSCAPE_PRIMARY.
-  test_api.SetDisplayRotation(display::Display::ROTATE_0,
-                              display::Display::RotationSource::ACTIVE);
-  EXPECT_EQ(test_api.GetCurrentOrientation(),
-            OrientationLockType::kLandscapePrimary);
-
-  std::unique_ptr<aura::Window> window = CreateTestWindowWithWidget();
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
-
-  // Drag the window a small distance that will not drop the window into
-  // overview.
-  base::TimeTicks timestamp = base::TimeTicks::Now();
-  SendScrollStartAndUpdate(gfx::Point(0, 0), 10, timestamp, window.get());
-  OverviewController* overview_controller = Shell::Get()->overview_controller();
-  EXPECT_TRUE(overview_controller->IsSelecting());
-  EXPECT_TRUE(wm::GetWindowState(window.get())->is_dragged());
-
-  // Rotate the screen during drag.
-  test_api.SetDisplayRotation(display::Display::ROTATE_270,
-                              display::Display::RotationSource::ACTIVE);
-  EXPECT_EQ(test_api.GetCurrentOrientation(),
-            OrientationLockType::kPortraitPrimary);
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
-  EXPECT_FALSE(overview_controller->IsSelecting());
-  EXPECT_FALSE(wm::GetWindowState(window.get())->is_dragged());
+  EXPECT_EQ(
+      split_view_controller()
+          ->GetSnappedWindowBoundsInScreen(window(), SplitViewController::LEFT)
+          .height(),
+      display_bounds.height());
 }
 
 // Tests the functionalities that fling the window when preview area is shown.
 TEST_F(SplitViewAppDraggingTest, FlingWhenPreviewAreaIsShown) {
-  std::unique_ptr<aura::Window> window = CreateTestWindowWithWidget();
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
+  InitializeWindow();
+  EXPECT_TRUE(wm::GetWindowState(window())->IsMaximized());
   gfx::Rect display_bounds =
       screen_util::GetDisplayWorkAreaBoundsInScreenForDefaultContainer(
-          window.get());
+          window());
 
   const float long_scroll_delta = display_bounds.height() / 4 + 5;
   float large_velocity =
@@ -3809,64 +3758,63 @@
 
   // Fling to the right with large enough velocity when trying to snap the
   // window to the left should drop the window to overview.
-  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get());
+  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp);
   EXPECT_EQ(IndicatorState::kPreviewAreaLeft, GetIndicatorState());
-  EndScrollSequence(start, long_scroll_delta, timestamp, window.get(),
-                    /*is_fling=*/true, /*velocity_y*/ 0,
-                    /*velocity_x=*/large_velocity);
+  Fling(start, long_scroll_delta, timestamp,
+        /*velocity_y*/ 0,
+        /*velocity_x=*/large_velocity);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   OverviewSession* overview_session = overview_controller->overview_session();
   EXPECT_TRUE(overview_controller->IsSelecting());
-  EXPECT_TRUE(overview_session->IsWindowInOverview(window.get()));
+  EXPECT_TRUE(overview_session->IsWindowInOverview(window()));
   ToggleOverview();
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
+  EXPECT_TRUE(wm::GetWindowState(window())->IsMaximized());
 
   // Fling to the right with small velocity when trying to snap the
   // window to the left should still snap the window to left.
-  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get());
+  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp);
   EXPECT_EQ(IndicatorState::kPreviewAreaLeft, GetIndicatorState());
-  EndScrollSequence(start, long_scroll_delta, timestamp, window.get(),
-                    /*is_fling=*/true, /*velocity_y*/ 0,
-                    /*velocity_x=*/small_velocity);
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsSnapped());
+  Fling(start, long_scroll_delta, timestamp,
+        /*velocity_y*/ 0,
+        /*velocity_x=*/small_velocity);
+  EXPECT_TRUE(wm::GetWindowState(window())->IsSnapped());
   EndSplitView();
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
+  EXPECT_TRUE(wm::GetWindowState(window())->IsMaximized());
 
   // Fling to the left with large enough velocity when trying to snap the window
   // to the right should drop the window to overvie.
   start = gfx::Point(display_bounds.right(), 0);
-  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get());
+  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp);
   EXPECT_EQ(IndicatorState::kPreviewAreaRight, GetIndicatorState());
-  EndScrollSequence(start, long_scroll_delta, timestamp, window.get(),
-                    /*is_fling=*/true, /*velocity_y*/ 0,
-                    /*velocity_x=*/-large_velocity);
+  Fling(start, long_scroll_delta, timestamp, /*velocity_y*/ 0,
+        /*velocity_x=*/-large_velocity);
   overview_session = overview_controller->overview_session();
   EXPECT_TRUE(overview_controller->IsSelecting());
-  EXPECT_TRUE(overview_session->IsWindowInOverview(window.get()));
+  EXPECT_TRUE(overview_session->IsWindowInOverview(window()));
   ToggleOverview();
 
   // Fling to the left with small velocity when trying to snap the
   // window to the right should still snap the window to right.
-  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get());
+  SendScrollStartAndUpdate(start, long_scroll_delta, timestamp);
   EXPECT_EQ(IndicatorState::kPreviewAreaRight, GetIndicatorState());
-  EndScrollSequence(start, long_scroll_delta, timestamp, window.get(),
-                    /*is_fling=*/true, /*velocity_y*/ 0,
-                    /*velocity_x=*/-small_velocity);
-  EXPECT_TRUE(wm::GetWindowState(window.get())->IsSnapped());
+  Fling(start, long_scroll_delta, timestamp,
+        /*velocity_y*/ 0,
+        /*velocity_x=*/-small_velocity);
+  EXPECT_TRUE(wm::GetWindowState(window())->IsSnapped());
 }
 
 // Tests the functionalities that fling a window when splitview is active.
 TEST_F(SplitViewAppDraggingTest, FlingWhenSplitViewIsActive) {
-  std::unique_ptr<aura::Window> window1 = CreateTestWindowWithWidget();
-  std::unique_ptr<aura::Window> window2 = CreateTestWindowWithWidget();
+  InitializeWindow();
+  std::unique_ptr<aura::Window> window2 = CreateTestWindowWithWidget(true);
 
-  split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
+  split_view_controller()->SnapWindow(window(), SplitViewController::LEFT);
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
 
   gfx::Rect display_bounds =
       screen_util::GetDisplayWorkAreaBoundsInScreenForDefaultContainer(
-          window1.get());
+          window());
   const float long_scroll_y = display_bounds.bottom() - 10;
   float large_velocity =
       TabletModeWindowDragDelegate::kFlingToOverviewFromSnappingAreaThreshold +
@@ -3876,54 +3824,55 @@
   // Fling the window in left snapping area to left should still snap the
   // window.
   base::TimeTicks timestamp = base::TimeTicks::Now();
-  SendScrollStartAndUpdate(start, long_scroll_y, timestamp, window1.get());
-  EndScrollSequence(start, long_scroll_y, timestamp, window1.get(),
-                    /*is_fling=*/true, /*velocity_y=*/0,
-                    /*velocity_x=*/-large_velocity);
-  EXPECT_TRUE(wm::GetWindowState(window1.get())->IsSnapped());
+  SendScrollStartAndUpdate(start, long_scroll_y, timestamp);
+  Fling(start, long_scroll_y, timestamp,
+        /*velocity_y=*/0,
+        /*velocity_x=*/-large_velocity);
+  EXPECT_TRUE(wm::GetWindowState(window())->IsSnapped());
   EXPECT_EQ(SplitViewController::BOTH_SNAPPED,
             split_view_controller()->state());
 
   // Fling the window in left snapping area to right should drop the window
   // into overview.
-  SendScrollStartAndUpdate(start, long_scroll_y, timestamp, window1.get());
-  EndScrollSequence(start, long_scroll_y, timestamp, window1.get(),
-                    /*is_fling=*/true, /*velocity_y=*/0,
-                    /*velocity_x=*/large_velocity);
+  timestamp += base::TimeDelta::FromMilliseconds(1000);
+  SendScrollStartAndUpdate(start, long_scroll_y, timestamp);
+  Fling(start, long_scroll_y, timestamp,
+        /*velocity_y=*/0,
+        /*velocity_x=*/large_velocity);
   OverviewController* selector_controller = Shell::Get()->overview_controller();
-  EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview(
-      window1.get()));
+  EXPECT_TRUE(
+      selector_controller->overview_session()->IsWindowInOverview(window()));
   EXPECT_EQ(SplitViewController::RIGHT_SNAPPED,
             split_view_controller()->state());
+  EXPECT_TRUE(IsTabletMode());
   ToggleOverview();
+  EXPECT_TRUE(IsTabletMode());
 
   // Fling the window in right snapping area to left should drop the window into
   // overview.
   EXPECT_EQ(SplitViewController::BOTH_SNAPPED,
             split_view_controller()->state());
   const int scroll_x = display_bounds.CenterPoint().x() + 10;
-  SendScrollStartAndUpdate(start, long_scroll_y, timestamp, window1.get(),
-                           scroll_x);
+  SendScrollStartAndUpdate(start, long_scroll_y, timestamp, scroll_x);
   gfx::Point end(scroll_x, 0);
-  EndScrollSequence(end, long_scroll_y, timestamp, window1.get(),
-                    /*is_fling=*/true, /*velocity_y=*/0,
-                    /*velocity_x=*/-large_velocity);
-  EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview(
-      window1.get()));
+  Fling(end, long_scroll_y, timestamp,
+        /*velocity_y=*/0,
+        /*velocity_x=*/-large_velocity);
+  EXPECT_TRUE(
+      selector_controller->overview_session()->IsWindowInOverview(window()));
   EXPECT_EQ(SplitViewController::RIGHT_SNAPPED,
             split_view_controller()->state());
   ToggleOverview();
 
   // Fling the window in right snapping area to right should snap the window to
   // right side.
-  EXPECT_EQ(SplitViewController::BOTH_SNAPPED,
-            split_view_controller()->state());
-  SendScrollStartAndUpdate(start, long_scroll_y, timestamp, window1.get(),
-                           scroll_x);
-  EndScrollSequence(end, long_scroll_y, timestamp, window1.get(),
-                    /*is_fling=*/true, /*velocity_y=*/0,
-                    /*velocity_x=*/large_velocity);
-  EXPECT_EQ(split_view_controller()->right_window(), window1.get());
+  // EXPECT_EQ(SplitViewController::BOTH_SNAPPED,
+  //           split_view_controller()->state());
+  SendScrollStartAndUpdate(start, long_scroll_y, timestamp, scroll_x);
+  Fling(end, long_scroll_y, timestamp,
+        /*velocity_y=*/0,
+        /*velocity_x=*/large_velocity);
+  EXPECT_EQ(split_view_controller()->right_window(), window());
   EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview(
       window2.get()));
   EXPECT_EQ(SplitViewController::RIGHT_SNAPPED,
diff --git a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc
deleted file mode 100644
index 1328fa4..0000000
--- a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc
+++ /dev/null
@@ -1,140 +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 "ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h"
-
-#include "ash/shell.h"
-#include "ash/wm/overview/overview_controller.h"
-#include "ash/wm/splitview/split_view_drag_indicators.h"
-#include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h"
-#include "ash/wm/window_state.h"
-#include "ui/base/hit_test.h"
-#include "ui/views/widget/widget.h"
-#include "ui/wm/core/coordinate_conversion.h"
-
-namespace ash {
-
-namespace {
-
-// The drag delegate for app windows. It not only includes the logic in
-// TabletModeWindowDragDelegate, but also has special logic for app windows.
-class TabletModeAppWindowDragDelegate : public TabletModeWindowDragDelegate {
- public:
-  TabletModeAppWindowDragDelegate() = default;
-  ~TabletModeAppWindowDragDelegate() override = default;
-
- private:
-  // TabletModeWindowDragDelegate:
-  void PrepareWindowDrag(const gfx::Point& location_in_screen) override {
-    wm::GetWindowState(dragged_window_)
-        ->CreateDragDetails(location_in_screen, HTCLIENT,
-                            ::wm::WINDOW_MOVE_SOURCE_TOUCH);
-  }
-  void UpdateWindowDrag(const gfx::Point& location_in_screen) override {}
-  void EndingWindowDrag(wm::WmToplevelWindowEventHandler::DragResult result,
-                        const gfx::Point& location_in_screen) override {
-    wm::GetWindowState(dragged_window_)->DeleteDragDetails();
-  }
-  void EndedWindowDrag(const gfx::Point& location_in_screen) override {}
-  void StartFling(const ui::GestureEvent* event) override {
-    if (ShouldFlingIntoOverview(event)) {
-      DCHECK(Shell::Get()->overview_controller()->IsSelecting());
-      Shell::Get()->overview_controller()->overview_session()->AddItem(
-          dragged_window_, /*reposition=*/true, /*animate=*/false);
-    }
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(TabletModeAppWindowDragDelegate);
-};
-
-}  // namespace
-
-TabletModeAppWindowDragController::TabletModeAppWindowDragController()
-    : drag_delegate_(std::make_unique<TabletModeAppWindowDragDelegate>()) {
-  display::Screen::GetScreen()->AddObserver(this);
-}
-
-TabletModeAppWindowDragController::~TabletModeAppWindowDragController() {
-  display::Screen::GetScreen()->RemoveObserver(this);
-}
-
-bool TabletModeAppWindowDragController::DragWindowFromTop(
-    ui::GestureEvent* event) {
-  previous_location_in_screen_ =
-      drag_delegate_->GetEventLocationInScreen(event);
-  if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN)
-    return StartWindowDrag(event);
-
-  if (!drag_delegate_->dragged_window())
-    return false;
-
-  if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
-    UpdateWindowDrag(event);
-    return true;
-  }
-
-  if (event->type() == ui::ET_GESTURE_SCROLL_END) {
-    EndWindowDrag(event, wm::WmToplevelWindowEventHandler::DragResult::SUCCESS);
-    return true;
-  }
-
-  if (event->type() == ui::ET_SCROLL_FLING_START) {
-    FlingOrSwipe(event);
-    return true;
-  }
-
-  EndWindowDrag(event, wm::WmToplevelWindowEventHandler::DragResult::REVERT);
-  return false;
-}
-
-bool TabletModeAppWindowDragController::StartWindowDrag(
-    ui::GestureEvent* event) {
-  views::Widget* widget = views::Widget::GetTopLevelWidgetForNativeView(
-      static_cast<aura::Window*>(event->target()));
-  if (!widget)
-    return false;
-
-  drag_delegate_->StartWindowDrag(
-      widget->GetNativeWindow(),
-      drag_delegate_->GetEventLocationInScreen(event));
-  return true;
-}
-
-void TabletModeAppWindowDragController::UpdateWindowDrag(
-    ui::GestureEvent* event) {
-  // Update the dragged window's tranform during dragging.
-  drag_delegate_->ContinueWindowDrag(
-      drag_delegate_->GetEventLocationInScreen(event),
-      TabletModeWindowDragDelegate::UpdateDraggedWindowType::UPDATE_TRANSFORM);
-}
-
-void TabletModeAppWindowDragController::EndWindowDrag(
-    ui::GestureEvent* event,
-    wm::WmToplevelWindowEventHandler::DragResult result) {
-  drag_delegate_->EndWindowDrag(
-      result, drag_delegate_->GetEventLocationInScreen(event));
-}
-
-void TabletModeAppWindowDragController::FlingOrSwipe(ui::GestureEvent* event) {
-  drag_delegate_->FlingOrSwipe(event);
-}
-
-void TabletModeAppWindowDragController::OnDisplayMetricsChanged(
-    const display::Display& display,
-    uint32_t metrics) {
-  if (!drag_delegate_->dragged_window() || !(metrics & DISPLAY_METRIC_ROTATION))
-    return;
-
-  display::Display current_display =
-      display::Screen::GetScreen()->GetDisplayNearestWindow(
-          drag_delegate_->dragged_window());
-  if (display.id() != current_display.id())
-    return;
-
-  drag_delegate_->EndWindowDrag(
-      wm::WmToplevelWindowEventHandler::DragResult::REVERT,
-      previous_location_in_screen_);
-}
-
-}  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h
deleted file mode 100644
index 67eb701..0000000
--- a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h
+++ /dev/null
@@ -1,55 +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 ASH_WM_TABLET_MODE_TABLET_MODE_APP_WINDOW_DRAG_CONTROLLER_H_
-#define ASH_WM_TABLET_MODE_TABLET_MODE_APP_WINDOW_DRAG_CONTROLLER_H_
-
-#include "ash/ash_export.h"
-#include "ash/wm/wm_toplevel_window_event_handler.h"
-#include "ui/display/display_observer.h"
-
-namespace ui {
-class GestureEvent;
-}  // namespace ui
-
-namespace ash {
-class TabletModeWindowDragDelegate;
-
-// Handles app windows dragging in tablet mode. App windows can be dragged into
-// splitscreen through swiping from the top of the screen in tablet mode.
-class ASH_EXPORT TabletModeAppWindowDragController
-    : public display::DisplayObserver {
- public:
-  TabletModeAppWindowDragController();
-  ~TabletModeAppWindowDragController() override;
-
-  // Processes a gesture event and updates the transform of |dragged_window_|.
-  // Returns true if the gesture has been handled and it should not be processed
-  // any further, false otherwise. Depending on the event position, the dragged
-  // window may be 1) maximized, or 2) snapped in splitscren.
-  bool DragWindowFromTop(ui::GestureEvent* event);
-
-  TabletModeWindowDragDelegate* drag_delegate() { return drag_delegate_.get(); }
-
- private:
-  // Gesture window drag related functions. Used in DragWindowFromTop.
-  bool StartWindowDrag(ui::GestureEvent* event);
-  void UpdateWindowDrag(ui::GestureEvent* event);
-  void EndWindowDrag(ui::GestureEvent* event,
-                     wm::WmToplevelWindowEventHandler::DragResult result);
-  void FlingOrSwipe(ui::GestureEvent* event);
-
-  // display::DisplayObserver:
-  void OnDisplayMetricsChanged(const display::Display& display,
-                               uint32_t metrics) override;
-
-  std::unique_ptr<TabletModeWindowDragDelegate> drag_delegate_;
-  gfx::Point previous_location_in_screen_;
-
-  DISALLOW_COPY_AND_ASSIGN(TabletModeAppWindowDragController);
-};
-
-}  // namespace ash
-
-#endif  // ASH_WM_TABLET_MODE_TABLET_MODE_APP_WINDOW_DRAG_CONTROLLER_H_
diff --git a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.h b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.h
deleted file mode 100644
index ec7b5877..0000000
--- a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.h
+++ /dev/null
@@ -1,61 +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 ASH_WM_TABLET_MODE_TABLET_MODE_BROWSER_WINDOW_DRAG_CONTROLLER_H_
-#define ASH_WM_TABLET_MODE_TABLET_MODE_BROWSER_WINDOW_DRAG_CONTROLLER_H_
-
-#include <memory>
-
-#include "ash/wm/window_resizer.h"
-#include "ash/wm/wm_toplevel_window_event_handler.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-
-namespace ash {
-class TabletModeWindowDragDelegate;
-
-namespace wm {
-class WindowState;
-}  // namespace wm
-
-// WindowResizer implementation for browser windows in tablet mode. Currently we
-// don't allow any resizing and any dragging happening on the area other than
-// the caption tabs area in tablet mode. Only browser windows with tabs are
-// allowed to be dragged. Depending on the event position, the dragged window
-// may be 1) maximized, or 2) snapped in splitscreen, or 3) merged to an
-// existing window.
-class TabletModeBrowserWindowDragController : public WindowResizer {
- public:
-  explicit TabletModeBrowserWindowDragController(wm::WindowState* window_state);
-  ~TabletModeBrowserWindowDragController() override;
-
-  // WindowResizer:
-  void Drag(const gfx::Point& location_in_parent, int event_flags) override;
-  void CompleteDrag() override;
-  void RevertDrag() override;
-  void FlingOrSwipe(ui::GestureEvent* event) override;
-
-  TabletModeWindowDragDelegate* drag_delegate_for_testing() {
-    return drag_delegate_.get();
-  }
-
- private:
-  // The drag delegate that does the real work: shows/hides the drag indicators,
-  // preview windows, blurred background, etc, during dragging.
-  std::unique_ptr<TabletModeWindowDragDelegate> drag_delegate_;
-
-  gfx::Point previous_location_in_screen_;
-
-  bool did_lock_cursor_ = false;
-
-  // Used to determine if this has been deleted during a drag such as when a tab
-  // gets dragged into another browser window.
-  base::WeakPtrFactory<TabletModeBrowserWindowDragController> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(TabletModeBrowserWindowDragController);
-};
-
-}  // namespace ash
-
-#endif  // ASH_WM_TABLET_MODE_TABLET_MODE_BROWSER_WINDOW_DRAG_CONTROLLER_H_
diff --git a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
index b35513c..8cdacc0d 100644
--- a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
+++ b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
@@ -17,7 +17,6 @@
 #include "ash/wm/overview/overview_grid.h"
 #include "ash/wm/overview/overview_utils.h"
 #include "ash/wm/splitview/split_view_constants.h"
-#include "ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_window_state.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/window.h"
diff --git a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h
index b39a3ea..4767324 100644
--- a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h
+++ b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h
@@ -5,6 +5,7 @@
 #ifndef ASH_WM_TABLET_MODE_TABLET_MODE_BROWSER_WINDOW_DRAG_DELEGATE_H_
 #define ASH_WM_TABLET_MODE_TABLET_MODE_BROWSER_WINDOW_DRAG_DELEGATE_H_
 
+#include "ash/ash_export.h"
 #include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h"
 #include "base/macros.h"
 
@@ -14,7 +15,7 @@
 // TabletModeWindowDragDelegate, but also has special logic for browser windows,
 // e.g., scales the source window, shows/hides the other windows below the
 // source window.
-class TabletModeBrowserWindowDragDelegate
+class ASH_EXPORT TabletModeBrowserWindowDragDelegate
     : public TabletModeWindowDragDelegate {
  public:
   TabletModeBrowserWindowDragDelegate();
diff --git a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.cc b/ash/wm/tablet_mode/tablet_mode_window_drag_controller.cc
similarity index 73%
rename from ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.cc
rename to ash/wm/tablet_mode/tablet_mode_window_drag_controller.cc
index 06afd86..6c06533 100644
--- a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_drag_controller.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 "ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_window_drag_controller.h"
 
 #include "ash/shell.h"
 #include "ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h"
@@ -12,14 +12,12 @@
 
 namespace ash {
 
-TabletModeBrowserWindowDragController::TabletModeBrowserWindowDragController(
-    wm::WindowState* window_state)
+TabletModeWindowDragController::TabletModeWindowDragController(
+    wm::WindowState* window_state,
+    std::unique_ptr<TabletModeWindowDragDelegate> drag_delegate)
     : WindowResizer(window_state),
-      drag_delegate_(std::make_unique<TabletModeBrowserWindowDragDelegate>()),
+      drag_delegate_(std::move(drag_delegate)),
       weak_ptr_factory_(this) {
-  DCHECK(details().is_resizable);
-  DCHECK(!window_state->allow_set_bounds_direct());
-
   if (details().source != ::wm::WINDOW_MOVE_SOURCE_TOUCH) {
     Shell::Get()->cursor_manager()->LockCursor();
     did_lock_cursor_ = true;
@@ -32,15 +30,13 @@
   drag_delegate_->StartWindowDrag(GetTarget(), previous_location_in_screen_);
 }
 
-TabletModeBrowserWindowDragController::
-    ~TabletModeBrowserWindowDragController() {
+TabletModeWindowDragController::~TabletModeWindowDragController() {
   if (did_lock_cursor_)
     Shell::Get()->cursor_manager()->UnlockCursor();
 }
 
-void TabletModeBrowserWindowDragController::Drag(
-    const gfx::Point& location_in_parent,
-    int event_flags) {
+void TabletModeWindowDragController::Drag(const gfx::Point& location_in_parent,
+                                          int event_flags) {
   gfx::Point location_in_screen = location_in_parent;
   ::wm::ConvertPointToScreen(GetTarget()->parent(), &location_in_screen);
   previous_location_in_screen_ = location_in_screen;
@@ -49,7 +45,7 @@
   // source window position, blurred background, etc, if necessary.
   if (wm::IsDraggingTabs(GetTarget())) {
     // Update the dragged window's bounds if it's tab-dragging.
-    base::WeakPtr<TabletModeBrowserWindowDragController> resizer(
+    base::WeakPtr<TabletModeWindowDragController> resizer(
         weak_ptr_factory_.GetWeakPtr());
     drag_delegate_->ContinueWindowDrag(
         location_in_screen,
@@ -66,20 +62,19 @@
   }
 }
 
-void TabletModeBrowserWindowDragController::CompleteDrag() {
+void TabletModeWindowDragController::CompleteDrag() {
   drag_delegate_->EndWindowDrag(
       wm::WmToplevelWindowEventHandler::DragResult::SUCCESS,
       previous_location_in_screen_);
 }
 
-void TabletModeBrowserWindowDragController::RevertDrag() {
+void TabletModeWindowDragController::RevertDrag() {
   drag_delegate_->EndWindowDrag(
       wm::WmToplevelWindowEventHandler::DragResult::REVERT,
       previous_location_in_screen_);
 }
 
-void TabletModeBrowserWindowDragController::FlingOrSwipe(
-    ui::GestureEvent* event) {
+void TabletModeWindowDragController::FlingOrSwipe(ui::GestureEvent* event) {
   drag_delegate_->FlingOrSwipe(event);
 }
 
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_controller.h b/ash/wm/tablet_mode/tablet_mode_window_drag_controller.h
new file mode 100644
index 0000000..1c670226
--- /dev/null
+++ b/ash/wm/tablet_mode/tablet_mode_window_drag_controller.h
@@ -0,0 +1,64 @@
+// 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 ASH_WM_TABLET_MODE_TABLET_MODE_WINDOW_DRAG_CONTROLLER_H_
+#define ASH_WM_TABLET_MODE_TABLET_MODE_WINDOW_DRAG_CONTROLLER_H_
+
+#include <memory>
+
+#include "ash/ash_export.h"
+#include "ash/wm/window_resizer.h"
+#include "ash/wm/wm_toplevel_window_event_handler.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+
+namespace ash {
+class TabletModeWindowDragDelegate;
+
+namespace wm {
+class WindowState;
+}  // namespace wm
+
+// WindowResizer implementation for windows in tablet mode. Currently we
+// don't allow any resizing and any dragging happening on the area other than
+// the caption tabs area in tablet mode, or the top few client pixels for app
+// windows without caption areas. Depending on the event position, the dragged
+// window may be 1) maximized, or 2) snapped in splitscreen, or 3) merged to an
+// existing window (in the case of a browser window).
+class ASH_EXPORT TabletModeWindowDragController : public WindowResizer {
+ public:
+  TabletModeWindowDragController(
+      wm::WindowState* window_state,
+      std::unique_ptr<TabletModeWindowDragDelegate> drag_delegate);
+  ~TabletModeWindowDragController() override;
+
+  // WindowResizer:
+  void Drag(const gfx::Point& location_in_parent, int event_flags) override;
+  void CompleteDrag() override;
+  void RevertDrag() override;
+  void FlingOrSwipe(ui::GestureEvent* event) override;
+
+  TabletModeWindowDragDelegate* drag_delegate_for_testing() {
+    return drag_delegate_.get();
+  }
+
+ private:
+  // The drag delegate that does the real work: shows/hides the drag indicators,
+  // preview windows, blurred background, etc, during dragging.
+  std::unique_ptr<TabletModeWindowDragDelegate> drag_delegate_;
+
+  gfx::Point previous_location_in_screen_;
+
+  bool did_lock_cursor_ = false;
+
+  // Used to determine if this has been deleted during a drag such as when a tab
+  // gets dragged into another browser window.
+  base::WeakPtrFactory<TabletModeWindowDragController> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabletModeWindowDragController);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_TABLET_MODE_TABLET_MODE_WINDOW_DRAG_CONTROLLER_H_
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 725799a..74fc9c3 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
@@ -107,7 +107,6 @@
   // If the dragged window is one of the snapped windows, SplitViewController
   // might open overview in the dragged window side of the screen.
   split_view_controller_->OnWindowDragStarted(dragged_window_);
-
   if (ShouldOpenOverviewWhenDragStarts() && !controller->IsSelecting()) {
     controller->ToggleOverview(
         OverviewSession::EnterExitOverviewType::kWindowDragged);
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 6d40488..a4698a12 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -17,7 +17,6 @@
 #include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/wm/default_state.h"
-#include "ash/wm/immersive_gesture_drag_handler.h"
 #include "ash/wm/pip/pip_positioner.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_animations.h"
@@ -786,16 +785,6 @@
       // on our changed state.
       ash::Shell::Get()->UpdateShelfVisibility();
     }
-    if (key == kImmersiveIsActive) {
-      if (IsInImmersiveFullscreen()) {
-        if (!immersive_gesture_drag_handler_) {
-          immersive_gesture_drag_handler_ =
-              std::make_unique<ImmersiveGestureDragHandler>(window);
-        }
-      } else {
-        immersive_gesture_drag_handler_.reset();
-      }
-    }
     return;
   }
 }
@@ -813,7 +802,6 @@
   if (widget)
     Shell::Get()->focus_cycler()->RemoveWidget(widget);
 
-  immersive_gesture_drag_handler_.reset();
   current_state_->OnWindowDestroying(this);
   delegate_.reset();
 }
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index 8eda1f35..256b961 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -26,7 +26,6 @@
 }
 
 namespace ash {
-class ImmersiveGestureDragHandler;
 class LockWindowState;
 class TabletModeWindowState;
 
@@ -468,10 +467,6 @@
 
   std::unique_ptr<State> current_state_;
 
-  // An object that assists with dragging immersive mode windows in tablet mode.
-  // Only non-null when immersive mode is active.
-  std::unique_ptr<ImmersiveGestureDragHandler> immersive_gesture_drag_handler_;
-
   DISALLOW_COPY_AND_ASSIGN(WindowState);
 };
 
diff --git a/ash/wm/wm_toplevel_window_event_handler.cc b/ash/wm/wm_toplevel_window_event_handler.cc
index f6ad708..2db4efe 100644
--- a/ash/wm/wm_toplevel_window_event_handler.cc
+++ b/ash/wm/wm_toplevel_window_event_handler.cc
@@ -4,6 +4,7 @@
 
 #include "ash/wm/wm_toplevel_window_event_handler.h"
 
+#include "ash/public/cpp/app_types.h"
 #include "ash/shell.h"
 #include "ash/wm/resize_shadow_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
@@ -12,12 +13,16 @@
 #include "ash/wm/window_state_observer.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_event.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/window_types.h"
+#include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/aura/window_observer.h"
 #include "ui/base/hit_test.h"
 #include "ui/events/event.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+#include "ui/views/widget/widget.h"
 #include "ui/wm/core/coordinate_conversion.h"
 
 namespace ash {
@@ -25,6 +30,69 @@
 
 namespace {
 
+// How many pixels are reserved for gesture events to start dragging the app
+// window from the top of the screen in tablet mode.
+constexpr int kDragStartTopEdgeInset = 8;
+
+// Returns the toplevel window that should be dragged for a gesture event that
+// occurs in the HTCLIENT area of a window. Returns null if there shouldn't be
+// special casing for this HTCLIENT area gesture. This is used to drag app
+// windows which are fullscreened/maximized in tablet mode from the top of the
+// screen, which don't have a window frame.
+aura::Window* GetTargetForClientAreaGesture(ui::GestureEvent* event,
+                                            aura::Window* target) {
+  if (event->type() != ui::ET_GESTURE_SCROLL_BEGIN)
+    return nullptr;
+
+  if (!Shell::Get()
+           ->tablet_mode_controller()
+           ->IsTabletModeWindowManagerEnabled()) {
+    return nullptr;
+  }
+
+  views::Widget* widget = views::Widget::GetTopLevelWidgetForNativeView(target);
+  if (!widget)
+    return nullptr;
+
+  aura::Window* toplevel = widget->GetNativeWindow();
+  wm::WindowState* window_state = wm::GetWindowState(toplevel);
+  if (!window_state ||
+      (!window_state->IsMaximized() && !window_state->IsFullscreen() &&
+       !window_state->IsSnapped())) {
+    return nullptr;
+  }
+
+  if (toplevel->GetProperty(aura::client::kAppType) ==
+      static_cast<int>(AppType::BROWSER)) {
+    return nullptr;
+  }
+
+  if (event->details().scroll_y_hint() < 0)
+    return nullptr;
+
+  const gfx::Point location_in_screen =
+      event->target()->GetScreenLocation(*event);
+  const gfx::Rect work_area_bounds =
+      display::Screen::GetScreen()
+          ->GetDisplayNearestWindow(static_cast<aura::Window*>(event->target()))
+          .work_area();
+
+  gfx::Rect hit_bounds_in_screen(work_area_bounds);
+  hit_bounds_in_screen.set_height(kDragStartTopEdgeInset);
+
+  // There may be a bezel sensor off screen logically above
+  // |hit_bounds_in_screen|. Handles the ET_GESTURE_SCROLL_BEGIN event
+  // triggered in the bezel area too.
+  bool in_bezel = location_in_screen.y() < hit_bounds_in_screen.y() &&
+                  location_in_screen.x() >= hit_bounds_in_screen.x() &&
+                  location_in_screen.x() < hit_bounds_in_screen.right();
+
+  if (hit_bounds_in_screen.Contains(location_in_screen) || in_bezel)
+    return toplevel;
+
+  return nullptr;
+}
+
 // Returns whether |window| can be moved via a two finger drag given
 // the hittest results of the two fingers.
 bool CanStartTwoFingerMove(aura::Window* window,
@@ -157,12 +225,29 @@
 WmToplevelWindowEventHandler::WmToplevelWindowEventHandler()
     : first_finger_hittest_(HTNOWHERE) {
   Shell::Get()->window_tree_host_manager()->AddObserver(this);
+  display::Screen::GetScreen()->AddObserver(this);
 }
 
 WmToplevelWindowEventHandler::~WmToplevelWindowEventHandler() {
+  display::Screen::GetScreen()->RemoveObserver(this);
   Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
 }
 
+void WmToplevelWindowEventHandler::OnDisplayMetricsChanged(
+    const display::Display& display,
+    uint32_t metrics) {
+  if (!window_resizer_ || !(metrics & DISPLAY_METRIC_ROTATION))
+    return;
+
+  display::Display current_display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(
+          window_resizer_->resizer()->GetTarget());
+  if (display.id() != current_display.id())
+    return;
+
+  RevertDrag();
+}
+
 void WmToplevelWindowEventHandler::OnKeyEvent(ui::KeyEvent* event) {
   if (window_resizer_.get() && event->type() == ui::ET_KEY_PRESSED &&
       event->key_code() == ui::VKEY_ESCAPE) {
@@ -213,23 +298,51 @@
 
 void WmToplevelWindowEventHandler::OnGestureEvent(ui::GestureEvent* event,
                                                   aura::Window* target) {
+  DCHECK_EQ(event->target(), target);
+  int component = GetNonClientComponent(target, event->location());
+  gfx::Point event_location = event->location();
+
+  aura::Window* original_target = target;
+  bool client_area_drag = false;
+  if (component == HTCLIENT) {
+    // When dragging on a client area starts a gesture drag, |this| stops the
+    // propagation of the ET_GESTURE_SCROLL_BEGIN event. Subsequent gestures on
+    // the HTCLIENT area should also be stopped lest the client receive an
+    // ET_GESTURE_SCROLL_UPDATE without the ET_GESTURE_SCROLL_BEGIN.
+    if (in_gesture_drag_ && target != gesture_target_) {
+      event->StopPropagation();
+      return;
+    }
+
+    aura::Window* new_target = GetTargetForClientAreaGesture(event, target);
+
+    client_area_drag = !!new_target;
+    if (new_target && (target != new_target)) {
+      DCHECK_EQ(ui::ET_GESTURE_SCROLL_BEGIN, event->type());
+      aura::Window::ConvertPointToTarget(target, new_target, &event_location);
+
+      original_target->env()->gesture_recognizer()->TransferEventsTo(
+          original_target, new_target, ui::TransferTouchesBehavior::kCancel);
+      UpdateGestureTarget(new_target, event_location);
+      target = new_target;
+    }
+  }
+
   if (event->type() == ui::ET_GESTURE_END)
     UpdateGestureTarget(nullptr);
   else if (event->type() == ui::ET_GESTURE_BEGIN)
-    UpdateGestureTarget(target, event->location());
+    UpdateGestureTarget(target, event_location);
 
   if (event->handled())
     return;
   if (!target->delegate())
     return;
 
-  if (window_resizer_.get() && !in_gesture_drag_)
+  if (window_resizer_ && !in_gesture_drag_)
     return;
 
-  if (window_resizer_.get() &&
-      window_resizer_->resizer()->GetTarget() != target) {
+  if (window_resizer_ && window_resizer_->resizer()->GetTarget() != target)
     return;
-  }
 
   if (event->details().touch_points() > 2) {
     if (CompleteDrag(DragResult::SUCCESS))
@@ -239,7 +352,6 @@
 
   switch (event->type()) {
     case ui::ET_GESTURE_TAP_DOWN: {
-      int component = GetNonClientComponent(target, event->location());
       if (!(WindowResizer::GetBoundsChangeForWindowComponent(component) &
             WindowResizer::kBoundsChange_Resizes))
         return;
@@ -249,9 +361,8 @@
     case ui::ET_GESTURE_END: {
       HideResizeShadow(target);
 
-      if (window_resizer_.get() &&
-          (event->details().touch_points() == 1 ||
-           !CanStartOneFingerDrag(first_finger_hittest_))) {
+      if (window_resizer_ && (event->details().touch_points() == 1 ||
+                              !CanStartOneFingerDrag(first_finger_hittest_))) {
         CompleteDrag(DragResult::SUCCESS);
         event->StopPropagation();
       }
@@ -259,12 +370,11 @@
     }
     case ui::ET_GESTURE_BEGIN: {
       if (event->details().touch_points() == 1) {
-        first_finger_touch_point_ = event->location();
+        first_finger_touch_point_ = event_location;
         aura::Window::ConvertPointToTarget(target, target->parent(),
                                            &first_finger_touch_point_);
-        first_finger_hittest_ =
-            GetNonClientComponent(target, event->location());
-      } else if (window_resizer_.get()) {
+        first_finger_hittest_ = component;
+      } else if (window_resizer_) {
         if (!window_resizer_->IsMove()) {
           // The transition from resizing with one finger to resizing with two
           // fingers causes unintended resizing because the location of
@@ -275,8 +385,7 @@
           event->StopPropagation();
         }
       } else {
-        int second_finger_hittest =
-            GetNonClientComponent(target, event->location());
+        int second_finger_hittest = component;
         if (CanStartTwoFingerMove(target, first_finger_hittest_,
                                   second_finger_hittest)) {
           AttemptToStartDrag(target, first_finger_touch_point_, HTCAPTION,
@@ -294,10 +403,11 @@
       // finger's position to the position in the middle of the two fingers.
       if (window_resizer_.get())
         return;
-      int component = GetNonClientComponent(target, event->location());
-      if (!CanStartOneFingerDrag(component))
+
+      if (!client_area_drag && !CanStartOneFingerDrag(component))
         return;
-      gfx::Point location_in_parent = event->location();
+
+      gfx::Point location_in_parent = event_location;
       aura::Window::ConvertPointToTarget(target, target->parent(),
                                          &location_in_parent);
       AttemptToStartDrag(target, location_in_parent, component,
diff --git a/ash/wm/wm_toplevel_window_event_handler.h b/ash/wm/wm_toplevel_window_event_handler.h
index 4c72b9f..12205ac 100644
--- a/ash/wm/wm_toplevel_window_event_handler.h
+++ b/ash/wm/wm_toplevel_window_event_handler.h
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "ui/aura/window_observer.h"
+#include "ui/display/display_observer.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/wm/public/window_move_client.h"
 
@@ -38,7 +39,8 @@
 // EventHandler.
 class ASH_EXPORT WmToplevelWindowEventHandler
     : public WindowTreeHostManager::Observer,
-      public aura::WindowObserver {
+      public aura::WindowObserver,
+      public display::DisplayObserver {
  public:
   // Describes what triggered ending the drag.
   enum class DragResult {
@@ -55,6 +57,10 @@
   WmToplevelWindowEventHandler();
   ~WmToplevelWindowEventHandler() override;
 
+  // display::DisplayObserver:
+  void OnDisplayMetricsChanged(const display::Display& display,
+                               uint32_t metrics) override;
+
   void OnKeyEvent(ui::KeyEvent* event);
   void OnMouseEvent(ui::MouseEvent* event, aura::Window* target);
   void OnGestureEvent(ui::GestureEvent* event, aura::Window* target);
diff --git a/ash/wm/wm_toplevel_window_event_handler_unittest.cc b/ash/wm/wm_toplevel_window_event_handler_unittest.cc
new file mode 100644
index 0000000..6dc246a
--- /dev/null
+++ b/ash/wm/wm_toplevel_window_event_handler_unittest.cc
@@ -0,0 +1,136 @@
+// 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 "ash/display/screen_orientation_controller.h"
+#include "ash/display/screen_orientation_controller_test_api.h"
+#include "ash/public/cpp/app_types.h"
+#include "ash/shell.h"
+#include "ash/system/overview/overview_button_tray.h"
+#include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/wm/overview/overview_controller.h"
+#include "ash/wm/overview/overview_grid.h"
+#include "ash/wm/overview/overview_item.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
+#include "ash/wm/toplevel_window_event_handler.h"
+#include "ash/wm/window_state.h"
+#include "base/time/time.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/display/test/display_manager_test_api.h"
+#include "ui/events/test/event_generator.h"
+
+namespace ash {
+
+class WmToplevelWindowEventHandlerTest : public AshTestBase {
+ public:
+  WmToplevelWindowEventHandlerTest() = default;
+  ~WmToplevelWindowEventHandlerTest() override = default;
+
+  void SetUp() override {
+    AshTestBase::SetUp();
+    TabletModeControllerTestApi().EnterTabletMode();
+
+    dragged_window_ = CreateTestWindow();
+    non_dragged_window_ = CreateTestWindow();
+    dragged_window_->SetProperty(aura::client::kAppType,
+                                 static_cast<int>(AppType::CHROME_APP));
+  }
+
+  void TearDown() override {
+    non_dragged_window_.reset();
+    dragged_window_.reset();
+    AshTestBase::TearDown();
+  }
+
+ protected:
+  // Send gesture event with |type| to the toplevel window event handler.
+  void SendGestureEvent(const gfx::Point& position,
+                        int scroll_x,
+                        int scroll_y,
+                        ui::EventType type) {
+    ui::GestureEvent event = ui::GestureEvent(
+        position.x(), position.y(), ui::EF_NONE, base::TimeTicks::Now(),
+        ui::GestureEventDetails(type, scroll_x, scroll_y));
+    ui::Event::DispatcherApi(&event).set_target(dragged_window_.get());
+    ash::Shell::Get()->toplevel_window_event_handler()->OnGestureEvent(&event);
+  }
+
+  std::unique_ptr<aura::Window> dragged_window_;
+  std::unique_ptr<aura::Window> non_dragged_window_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WmToplevelWindowEventHandlerTest);
+};
+
+// Tests that tap the window in overview grid during window drag should end
+// the overview mode.
+TEST_F(WmToplevelWindowEventHandlerTest,
+       TapWindowInOverviewGridDuringWindowDrag) {
+  ASSERT_TRUE(TabletModeControllerTestApi().IsTabletModeStarted());
+
+  SendGestureEvent(gfx::Point(0, 0), 0, 5, ui::ET_GESTURE_SCROLL_BEGIN);
+  // Drag the window to the right corner to avoid overlap with
+  // |non_dragged_window_| in overview grid.
+  SendGestureEvent(gfx::Point(700, 500), 700, 500,
+                   ui::ET_GESTURE_SCROLL_UPDATE);
+  EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->is_dragged());
+
+  OverviewController* overview_controller = Shell::Get()->overview_controller();
+  EXPECT_TRUE(overview_controller->IsSelecting());
+  EXPECT_TRUE(overview_controller->overview_session()->IsWindowInOverview(
+      non_dragged_window_.get()));
+
+  OverviewGrid* current_grid =
+      overview_controller->overview_session()->GetGridWithRootWindow(
+          non_dragged_window_->GetRootWindow());
+  OverviewItem* item =
+      current_grid->GetOverviewItemContaining(non_dragged_window_.get());
+  GetEventGenerator()->GestureTapAt(item->GetTransformedBounds().CenterPoint());
+
+  // Overview mode is no longer active and |non_dragged_window_| is not in the
+  // overview grid after tapping it in overview grid.
+  EXPECT_FALSE(overview_controller->IsSelecting());
+  EXPECT_FALSE(overview_controller->overview_session());
+}
+
+// Tests that the window drag will be reverted if the screen is being rotated.
+TEST_F(WmToplevelWindowEventHandlerTest, DisplayConfigurationChangeTest) {
+  int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+  display::DisplayManager* display_manager = Shell::Get()->display_manager();
+  display::test::ScopedSetInternalDisplayId set_internal(display_manager,
+                                                         display_id);
+  ScreenOrientationControllerTestApi test_api(
+      Shell::Get()->screen_orientation_controller());
+  // Set the screen orientation to LANDSCAPE_PRIMARY.
+  test_api.SetDisplayRotation(display::Display::ROTATE_0,
+                              display::Display::RotationSource::ACTIVE);
+  EXPECT_EQ(test_api.GetCurrentOrientation(),
+            OrientationLockType::kLandscapePrimary);
+
+  ASSERT_TRUE(TabletModeControllerTestApi().IsTabletModeStarted());
+
+  SendGestureEvent(gfx::Point(0, 0), 0, 5, ui::ET_GESTURE_SCROLL_BEGIN);
+  // Drag the window to the right corner to avoid overlap with
+  // |non_dragged_window_| in overview grid.
+  SendGestureEvent(gfx::Point(700, 500), 700, 500,
+                   ui::ET_GESTURE_SCROLL_UPDATE);
+  EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->is_dragged());
+
+  OverviewController* overview_controller = Shell::Get()->overview_controller();
+  EXPECT_TRUE(overview_controller->IsSelecting());
+  EXPECT_TRUE(overview_controller->overview_session()->IsWindowInOverview(
+      non_dragged_window_.get()));
+
+  // Rotate the screen during drag.
+  test_api.SetDisplayRotation(display::Display::ROTATE_270,
+                              display::Display::RotationSource::ACTIVE);
+  EXPECT_EQ(test_api.GetCurrentOrientation(),
+            OrientationLockType::kPortraitPrimary);
+  EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->IsMaximized());
+  EXPECT_FALSE(overview_controller->IsSelecting());
+  EXPECT_FALSE(wm::GetWindowState(dragged_window_.get())->is_dragged());
+}
+
+}  // namespace ash
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index cbb00b6a..5a656565 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -17,9 +17,12 @@
 #include "ash/shell.h"
 #include "ash/wm/default_window_resizer.h"
 #include "ash/wm/drag_window_resizer.h"
+#include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/pip/pip_window_resizer.h"
-#include "ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_window_drag_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h"
 #include "ash/wm/window_positioning_utils.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
@@ -41,24 +44,67 @@
 #include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/core/cursor_manager.h"
 
+namespace ash {
+
 namespace {
 
 constexpr double kMinHorizVelocityForWindowSwipe = 1100;
 constexpr double kMinVertVelocityForWindowMinimize = 1000;
 
+// The drag delegate for app windows. It not only includes the logic in
+// TabletModeWindowDragDelegate, but also has special logic for app windows.
+class TabletModeAppWindowDragDelegate : public TabletModeWindowDragDelegate {
+ public:
+  TabletModeAppWindowDragDelegate() = default;
+  ~TabletModeAppWindowDragDelegate() override = default;
+
+ private:
+  // TabletModeWindowDragDelegate:
+  void PrepareWindowDrag(const gfx::Point& location_in_screen) override {}
+  void UpdateWindowDrag(const gfx::Point& location_in_screen) override {}
+  void EndingWindowDrag(wm::WmToplevelWindowEventHandler::DragResult result,
+                        const gfx::Point& location_in_screen) override {}
+  void EndedWindowDrag(const gfx::Point& location_in_screen) override {}
+  void StartFling(const ui::GestureEvent* event) override {
+    if (ShouldFlingIntoOverview(event)) {
+      DCHECK(Shell::Get()->overview_controller()->IsSelecting());
+      Shell::Get()->overview_controller()->overview_session()->AddItem(
+          dragged_window_, /*reposition=*/true, /*animate=*/false);
+    }
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(TabletModeAppWindowDragDelegate);
+};
+
 // Returns true if |window| can be dragged from the top of the screen in tablet
 // mode.
-bool CanDragInTabletMode(aura::Window* window, int window_component) {
-  ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
-  // Pip window can't be dragged.
-  if (window_state->IsPip())
-    return false;
-
+std::unique_ptr<WindowResizer> CreateWindowResizerForTabletMode(
+    aura::Window* window,
+    const gfx::Point& point_in_parent,
+    int window_component,
+    ::wm::WindowMoveSource source) {
+  wm::WindowState* window_state = wm::GetWindowState(window);
   // Only maximized/fullscreen/snapped window can be dragged from the top of
   // the screen.
   if (!window_state->IsMaximized() && !window_state->IsFullscreen() &&
       !window_state->IsSnapped()) {
-    return false;
+    return nullptr;
+  }
+
+  AppType app_type =
+      static_cast<AppType>(window->GetProperty(aura::client::kAppType));
+  // App windows can be dragged from the client area (see
+  // WmToplevelWindowEventHandler).
+  if (app_type != AppType::BROWSER && window_component == HTCLIENT) {
+    DCHECK_EQ(source, ::wm::WINDOW_MOVE_SOURCE_TOUCH);
+    window_state->CreateDragDetails(point_in_parent, HTCLIENT,
+                                    ::wm::WINDOW_MOVE_SOURCE_TOUCH);
+    std::unique_ptr<WindowResizer> window_resizer =
+        std::make_unique<TabletModeWindowDragController>(
+            window_state, std::make_unique<TabletModeAppWindowDragDelegate>());
+    window_resizer = std::make_unique<DragWindowResizer>(
+        std::move(window_resizer), window_state);
+    return window_resizer;
   }
 
   // Only allow drag that happens on caption or top area. Note: for a maxmized
@@ -66,7 +112,7 @@
   // for a snapped window, the window component here can either be HTCAPTION or
   // HTTOP.
   if (window_component != HTCAPTION && window_component != HTTOP)
-    return false;
+    return nullptr;
 
   // Note: only browser windows and chrome app windows are included here.
   // For browser windows, this piece of codes will be called no matter the
@@ -74,31 +120,30 @@
   // But for app window, this piece of codes will only be called if the chrome
   // app window has its customized caption area and can't be hidden in tablet
   // mode (and thus the drag for this type of chrome app window always happens
-  // on caption or top area). If the caption area of the chrome app window can
-  // be hidden, ImmersiveGestureHandlerClassic will handle the window drag
-  // through TabletModeAppWindowDragController.
-  // TODO(xdai, minch): Merge the logic in ImmersiveGestureHandlerClassic into
-  // CreateWindowResizer() in future.
-  ash::AppType app_type =
-      static_cast<ash::AppType>(window->GetProperty(aura::client::kAppType));
-  if (app_type != ash::AppType::BROWSER &&
-      app_type != ash::AppType::CHROME_APP) {
-    return false;
-  }
+  // on caption or top area). The case where the caption area of the chrome app
+  // window can be hidden is handled above.
+  if (app_type != AppType::BROWSER && app_type != AppType::CHROME_APP)
+    return nullptr;
 
-  return true;
+  window_state->CreateDragDetails(point_in_parent, window_component, source);
+  std::unique_ptr<WindowResizer> window_resizer =
+      std::make_unique<TabletModeWindowDragController>(
+          window_state,
+          std::make_unique<TabletModeBrowserWindowDragDelegate>());
+  window_resizer = std::make_unique<DragWindowResizer>(
+      std::move(window_resizer), window_state);
+  return window_resizer;
 }
 
 }  // namespace
 
-namespace ash {
-
 std::unique_ptr<WindowResizer> CreateWindowResizer(
     aura::Window* window,
     const gfx::Point& point_in_parent,
     int window_component,
     ::wm::WindowMoveSource source) {
   DCHECK(window);
+
   wm::WindowState* window_state = wm::GetWindowState(window);
   // No need to return a resizer when the window cannot get resized or when a
   // resizer already exists for this window.
@@ -127,15 +172,8 @@
   if (Shell::Get()
           ->tablet_mode_controller()
           ->IsTabletModeWindowManagerEnabled()) {
-    if (!CanDragInTabletMode(window, window_component))
-      return nullptr;
-
-    window_state->CreateDragDetails(point_in_parent, window_component, source);
-    window_resizer =
-        std::make_unique<TabletModeBrowserWindowDragController>(window_state);
-    window_resizer = std::make_unique<DragWindowResizer>(
-        std::move(window_resizer), window_state);
-    return window_resizer;
+    return CreateWindowResizerForTabletMode(window, point_in_parent,
+                                            window_component, source);
   }
 
   if (!window_state->IsNormalOrSnapped())
diff --git a/base/BUILD.gn b/base/BUILD.gn
index a60bfea..6773a02 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1414,6 +1414,8 @@
       "fuchsia/service_directory.h",
       "fuchsia/service_directory_client.cc",
       "fuchsia/service_directory_client.h",
+      "fuchsia/service_provider_impl.cc",
+      "fuchsia/service_provider_impl.h",
       "memory/platform_shared_memory_region_fuchsia.cc",
       "memory/protected_memory_posix.cc",
       "memory/shared_memory_fuchsia.cc",
@@ -1477,6 +1479,7 @@
       "//third_party/fuchsia-sdk/sdk:async_loop_cpp",
       "//third_party/fuchsia-sdk/sdk:fidl",
       "//third_party/fuchsia-sdk/sdk:svc",
+      "//third_party/fuchsia-sdk/sdk:sys",
     ]
   }
 
@@ -2764,6 +2767,7 @@
       "fuchsia/service_directory_test_base.cc",
       "fuchsia/service_directory_test_base.h",
       "fuchsia/service_directory_unittest.cc",
+      "fuchsia/service_provider_impl_unittest.cc",
       "message_loop/message_loop_io_posix_unittest.cc",
       "posix/file_descriptor_shuffle_unittest.cc",
       "task/task_scheduler/task_tracker_posix_unittest.cc",
@@ -2778,6 +2782,7 @@
       "//third_party/fuchsia-sdk/sdk:async",
       "//third_party/fuchsia-sdk/sdk:async_default",
       "//third_party/fuchsia-sdk/sdk:fdio",
+      "//third_party/fuchsia-sdk/sdk:sys",
     ]
   }
 
diff --git a/base/fuchsia/service_provider_impl.cc b/base/fuchsia/service_provider_impl.cc
new file mode 100644
index 0000000..9a874ec1
--- /dev/null
+++ b/base/fuchsia/service_provider_impl.cc
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/fuchsia/service_provider_impl.h"
+
+#include <utility>
+
+namespace base {
+namespace fuchsia {
+
+ServiceProviderImpl::ServiceProviderImpl(
+    fidl::InterfaceHandle<::fuchsia::io::Directory> service_directory)
+    : directory_(std::move(service_directory)) {}
+
+ServiceProviderImpl::~ServiceProviderImpl() = default;
+
+void ServiceProviderImpl::AddBinding(
+    fidl::InterfaceRequest<::fuchsia::sys::ServiceProvider> request) {
+  bindings_.AddBinding(this, std::move(request));
+}
+
+void ServiceProviderImpl::ConnectToService(std::string service_name,
+                                           zx::channel client_handle) {
+  directory_.ConnectToServiceUnsafe(service_name.c_str(),
+                                    std::move(client_handle));
+}
+
+}  // namespace fuchsia
+}  // namespace base
diff --git a/base/fuchsia/service_provider_impl.h b/base/fuchsia/service_provider_impl.h
new file mode 100644
index 0000000..c7e56728
--- /dev/null
+++ b/base/fuchsia/service_provider_impl.h
@@ -0,0 +1,47 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FUCHSIA_SERVICE_PROVIDER_IMPL_H_
+#define BASE_FUCHSIA_SERVICE_PROVIDER_IMPL_H_
+
+#include <fuchsia/io/cpp/fidl.h>
+#include <fuchsia/sys/cpp/fidl.h>
+#include <lib/fidl/cpp/binding_set.h>
+#include <lib/fidl/cpp/interface_handle.h>
+#include <lib/zx/channel.h>
+#include <string>
+
+#include "base/fuchsia/service_directory_client.h"
+
+namespace base {
+namespace fuchsia {
+
+// Implementation of the legacy sys.ServiceProvider interface which delegates
+// requests to an underlying fuchsia.io.Directory of services.
+// TODO(https://crbug.com/920920): Remove this when ServiceProvider is gone.
+class BASE_EXPORT ServiceProviderImpl : public ::fuchsia::sys::ServiceProvider {
+ public:
+  explicit ServiceProviderImpl(
+      fidl::InterfaceHandle<::fuchsia::io::Directory> service_directory);
+  ~ServiceProviderImpl() override;
+
+  // Binds a |request| from a new client to be serviced by this ServiceProvider.
+  void AddBinding(
+      fidl::InterfaceRequest<::fuchsia::sys::ServiceProvider> request);
+
+ private:
+  // fuchsia::sys::ServiceProvider implementation.
+  void ConnectToService(std::string service_name,
+                        zx::channel client_handle) override;
+
+  const ServiceDirectoryClient directory_;
+  fidl::BindingSet<::fuchsia::sys::ServiceProvider> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceProviderImpl);
+};
+
+}  // namespace fuchsia
+}  // namespace base
+
+#endif  // BASE_FUCHSIA_SERVICE_PROVIDER_IMPL_H_
diff --git a/base/fuchsia/service_provider_impl_unittest.cc b/base/fuchsia/service_provider_impl_unittest.cc
new file mode 100644
index 0000000..9163031
--- /dev/null
+++ b/base/fuchsia/service_provider_impl_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/fuchsia/service_provider_impl.h"
+
+#include <lib/fdio/util.h>
+#include <lib/zx/channel.h>
+#include <utility>
+
+#include "base/fuchsia/scoped_service_binding.h"
+#include "base/fuchsia/service_directory.h"
+#include "base/fuchsia/test_interface_impl.h"
+#include "base/fuchsia/testfidl/cpp/fidl.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace fuchsia {
+
+class ServiceProviderImplTest : public testing::Test {
+ public:
+  ServiceProviderImplTest() = default;
+  ~ServiceProviderImplTest() override = default;
+
+  void VerifyTestInterface(fidl::InterfacePtr<testfidl::TestInterface>* stub,
+                           zx_status_t expected_error) {
+    // Call the service and wait for response.
+    base::RunLoop run_loop;
+    zx_status_t actual_error = ZX_OK;
+
+    stub->set_error_handler([&run_loop, &actual_error](zx_status_t status) {
+      actual_error = status;
+      run_loop.Quit();
+    });
+
+    (*stub)->Add(2, 2, [&run_loop](int32_t result) {
+      EXPECT_EQ(result, 4);
+      run_loop.Quit();
+    });
+
+    run_loop.Run();
+
+    EXPECT_EQ(expected_error, actual_error);
+
+    // Reset error handler because the current one captures |run_loop| and
+    // |error| references which are about to be destroyed.
+    stub->set_error_handler(nullptr);
+  }
+
+ protected:
+  MessageLoopForIO message_loop_;
+  TestInterfaceImpl test_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceProviderImplTest);
+};
+
+// Verifies that we can connect to the service service more than once.
+TEST_F(ServiceProviderImplTest, ConnectMulti) {
+  fidl::InterfaceHandle<::fuchsia::io::Directory> directory_channel;
+  ServiceDirectory service_directory(directory_channel.NewRequest());
+  ServiceProviderImpl provider_impl(std::move(directory_channel));
+  ScopedServiceBinding<testfidl::TestInterface> service_binding(
+      &service_directory, &test_service_);
+
+  ::fuchsia::sys::ServiceProviderPtr provider_client;
+  provider_impl.AddBinding(provider_client.NewRequest());
+
+  testfidl::TestInterfacePtr stub;
+  provider_client->ConnectToService(testfidl::TestInterface::Name_,
+                                    stub.NewRequest().TakeChannel());
+
+  testfidl::TestInterfacePtr stub2;
+  provider_client->ConnectToService(testfidl::TestInterface::Name_,
+                                    stub2.NewRequest().TakeChannel());
+
+  VerifyTestInterface(&stub, ZX_OK);
+  VerifyTestInterface(&stub2, ZX_OK);
+}
+
+// Verify that the case when the service doesn't exist is handled properly.
+TEST_F(ServiceProviderImplTest, NoService) {
+  fidl::InterfaceHandle<::fuchsia::io::Directory> directory_channel;
+  ServiceDirectory service_directory(directory_channel.NewRequest());
+  ServiceProviderImpl provider_impl(std::move(directory_channel));
+
+  ::fuchsia::sys::ServiceProviderPtr provider_client;
+  provider_impl.AddBinding(provider_client.NewRequest());
+
+  testfidl::TestInterfacePtr stub;
+  provider_client->ConnectToService(testfidl::TestInterface::Name_,
+                                    stub.NewRequest().TakeChannel());
+
+  VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED);
+}
+
+}  // namespace fuchsia
+}  // namespace base
diff --git a/base/sampling_heap_profiler/poisson_allocation_sampler.cc b/base/sampling_heap_profiler/poisson_allocation_sampler.cc
index eac17086..14f20a5 100644
--- a/base/sampling_heap_profiler/poisson_allocation_sampler.cc
+++ b/base/sampling_heap_profiler/poisson_allocation_sampler.cc
@@ -325,6 +325,11 @@
   TLSSetValue(g_internal_reentry_guard, false);
 }
 
+// static
+bool PoissonAllocationSampler::ScopedMuteThreadSamples::IsMuted() {
+  return TLSGetValue(g_internal_reentry_guard);
+}
+
 PoissonAllocationSampler* PoissonAllocationSampler::instance_;
 
 PoissonAllocationSampler::PoissonAllocationSampler() {
diff --git a/base/sampling_heap_profiler/poisson_allocation_sampler.h b/base/sampling_heap_profiler/poisson_allocation_sampler.h
index a55fdea..0dfb8b2a8 100644
--- a/base/sampling_heap_profiler/poisson_allocation_sampler.h
+++ b/base/sampling_heap_profiler/poisson_allocation_sampler.h
@@ -54,6 +54,8 @@
    public:
     ScopedMuteThreadSamples();
     ~ScopedMuteThreadSamples();
+
+    static bool IsMuted();
   };
 
   // Must be called early during the process initialization. It creates and
diff --git a/build/chromeos/test_runner.py b/build/chromeos/test_runner.py
index 6d55177d..e2d990a 100755
--- a/build/chromeos/test_runner.py
+++ b/build/chromeos/test_runner.py
@@ -198,6 +198,7 @@
         '--cmd',
         '--',
         'local_test_runner',
+        '-waituntilready',
     ]
     if self._use_vm:
       # If we're running tests in VMs, tell the test runner to skip tests that
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 1d1435c..68dc6a00 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1492,12 +1492,6 @@
         # TODO(thakis): https://crbug.com/617318
         # Currently goma can not handle case sensitiveness for windows well.
         cflags += [ "-Wno-nonportable-include-path" ]
-
-        if (target_cpu == "arm64") {
-          # Work around problem with SwiftShader for Windows ARM64
-          # TODO(Tom.Tan@microsoft.com): https://crbug.com/925595
-          cflags += [ "-Wno-defaulted-function-deleted" ]
-        }
       }
 
       if (current_toolchain == host_toolchain || !use_xcode_clang) {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index f4cf9c7..a05841a 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-3381b60b3e08a8c2655c1606bdb3f1983f2b6682
\ No newline at end of file
+022626e5320778cea154352d4592cc3d1686ef89
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index eefe7e3..933911e 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-87df02793ce594ee4619c23463a1c8b50ed50b8a
\ No newline at end of file
+4e0562dca48415b215553b5cf8032420ad66a25f
\ No newline at end of file
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index e088f60..1ab7be5 100755
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -42,7 +42,10 @@
   if ((sys.platform in ('win32', 'cygwin') or os.path.exists(json_data_file))
       and depot_tools_win_toolchain):
     if ShouldUpdateToolchain():
-      update_result = Update()
+      if len(sys.argv) > 1 and sys.argv[1] == 'update':
+        update_result = Update()
+      else:
+        update_result = Update(no_download=True)
       if update_result != 0:
         raise Exception('Failed to update, error code %d.' % update_result)
     with open(json_data_file, 'r') as tempf:
@@ -387,10 +390,12 @@
   return version != env_version
 
 
-def Update(force=False):
+def Update(force=False, no_download=False):
   """Requests an update of the toolchain to the specific hashes we have at
   this revision. The update outputs a .json of the various configuration
   information required to pass to gyp which we use in |GetToolchainDir()|.
+  If no_download is true then the toolchain will be configured if present but
+  will not be downloaded.
   """
   if force != False and force != '--force':
     print >>sys.stderr, 'Unknown parameter "%s"' % force
@@ -441,6 +446,8 @@
       ] + _GetDesiredVsToolchainHashes()
     if force:
       get_toolchain_args.append('--force')
+    if no_download:
+      get_toolchain_args.append('--no-download')
     subprocess.check_call(get_toolchain_args)
 
   return 0
diff --git a/cc/base/math_util.cc b/cc/base/math_util.cc
index d212a73..a484a24 100644
--- a/cc/base/math_util.cc
+++ b/cc/base/math_util.cc
@@ -20,6 +20,7 @@
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 #include "ui/gfx/geometry/vector3d_f.h"
+#include "ui/gfx/rrect_f.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
@@ -803,6 +804,25 @@
   res->EndArray();
 }
 
+void MathUtil::AddToTracedValue(const char* name,
+                                const gfx::RRectF& rect,
+                                base::trace_event::TracedValue* res) {
+  res->BeginArray(name);
+  res->AppendDouble(rect.rect().x());
+  res->AppendDouble(rect.rect().y());
+  res->AppendDouble(rect.rect().width());
+  res->AppendDouble(rect.rect().height());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kUpperLeft).x());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kUpperLeft).y());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kUpperRight).x());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kUpperRight).y());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerRight).x());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerRight).y());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerLeft).x());
+  res->AppendDouble(rect.GetCornerRadii(gfx::RRectF::Corner::kLowerLeft).y());
+  res->EndArray();
+}
+
 double MathUtil::AsDoubleSafely(double value) {
   return std::min(value, std::numeric_limits<double>::max());
 }
diff --git a/cc/base/math_util.h b/cc/base/math_util.h
index fd9855f..2674b83e 100644
--- a/cc/base/math_util.h
+++ b/cc/base/math_util.h
@@ -30,12 +30,13 @@
 class QuadF;
 class Rect;
 class RectF;
+class RRectF;
 class SizeF;
 class Transform;
 class Vector2dF;
 class Vector2d;
 class Vector3dF;
-}
+}  // namespace gfx
 
 namespace cc {
 
@@ -278,6 +279,9 @@
   static void AddToTracedValue(const char* name,
                                const gfx::BoxF& box,
                                base::trace_event::TracedValue* res);
+  static void AddToTracedValue(const char* name,
+                               const gfx::RRectF& rect,
+                               base::trace_event::TracedValue* res);
 
   // Returns a base::Value representation of the floating point value.
   // If the value is inf, returns max double/float representation.
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 18dc2f3..7ca1f364 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -563,7 +563,7 @@
   SetNeedsCommit();
 }
 
-void Layer::SetBackdropFilterBounds(const gfx::RectF& backdrop_filter_bounds) {
+void Layer::SetBackdropFilterBounds(const gfx::RRectF& backdrop_filter_bounds) {
   inputs_.backdrop_filter_bounds = backdrop_filter_bounds;
 }
 
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 286a72e..ebdeddf 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -34,8 +34,8 @@
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/point3_f.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/scroll_offset.h"
+#include "ui/gfx/rrect_f.h"
 #include "ui/gfx/transform.h"
 
 namespace base {
@@ -284,8 +284,8 @@
     return inputs_.backdrop_filters;
   }
 
-  void SetBackdropFilterBounds(const gfx::RectF& backdrop_filter_bounds);
-  const gfx::RectF& backdrop_filter_bounds() const {
+  void SetBackdropFilterBounds(const gfx::RRectF& backdrop_filter_bounds);
+  const gfx::RRectF& backdrop_filter_bounds() const {
     return inputs_.backdrop_filter_bounds;
   }
 
@@ -920,7 +920,7 @@
 
     FilterOperations filters;
     FilterOperations backdrop_filters;
-    gfx::RectF backdrop_filter_bounds;
+    gfx::RRectF backdrop_filter_bounds;
     gfx::PointF filters_origin;
     float backdrop_filter_quality;
 
diff --git a/cc/layers/layer_impl_test_properties.h b/cc/layers/layer_impl_test_properties.h
index 9f0d688a..c29aee7 100644
--- a/cc/layers/layer_impl_test_properties.h
+++ b/cc/layers/layer_impl_test_properties.h
@@ -16,6 +16,7 @@
 #include "cc/paint/filter_operations.h"
 #include "third_party/skia/include/core/SkBlendMode.h"
 #include "ui/gfx/geometry/point3_f.h"
+#include "ui/gfx/rrect_f.h"
 #include "ui/gfx/transform.h"
 
 namespace viz {
@@ -48,7 +49,7 @@
   float opacity;
   FilterOperations filters;
   FilterOperations backdrop_filters;
-  gfx::RectF backdrop_filter_bounds;
+  gfx::RRectF backdrop_filter_bounds;
   float backdrop_filter_quality;
   gfx::PointF filters_origin;
   SkBlendMode blend_mode;
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc
index 168de7b..6272461 100644
--- a/cc/layers/render_surface_impl.cc
+++ b/cc/layers/render_surface_impl.cc
@@ -153,7 +153,7 @@
   return OwningEffectNode()->backdrop_filters;
 }
 
-const gfx::RectF& RenderSurfaceImpl::BackdropFilterBounds() const {
+const gfx::RRectF& RenderSurfaceImpl::BackdropFilterBounds() const {
   return OwningEffectNode()->backdrop_filter_bounds;
 }
 
diff --git a/cc/layers/render_surface_impl.h b/cc/layers/render_surface_impl.h
index e3011ee3..58ae7f8 100644
--- a/cc/layers/render_surface_impl.h
+++ b/cc/layers/render_surface_impl.h
@@ -150,7 +150,7 @@
 
   const FilterOperations& Filters() const;
   const FilterOperations& BackdropFilters() const;
-  const gfx::RectF& BackdropFilterBounds() const;
+  const gfx::RRectF& BackdropFilterBounds() const;
   gfx::PointF FiltersOrigin() const;
   gfx::Transform SurfaceScale() const;
 
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
index a8b777f..b8854c46 100644
--- a/cc/paint/paint_op_reader.cc
+++ b/cc/paint/paint_op_reader.cc
@@ -33,9 +33,17 @@
          static_cast<uint8_t>(PaintShader::Type::kShaderCount);
 }
 
-bool IsValidSkShaderTileMode(SkShader::TileMode mode) {
-  // When Skia adds Decal, update this (skbug.com/7638)
-  return mode <= SkShader::kMirror_TileMode;
+// SkShader::TileMode has no defined backing type, so read/write int32_t's.
+// If read_mode is a valid tile mode, this returns true and updates mode to the
+// equivalent enum value. Otherwise false is returned and mode is not modified.
+bool ValidateAndGetSkShaderTileMode(int32_t read_mode,
+                                    SkShader::TileMode* mode) {
+  if (read_mode < 0 || read_mode >= SkShader::kTileModeCount) {
+    return false;
+  }
+
+  *mode = static_cast<SkShader::TileMode>(read_mode);
+  return true;
 }
 
 bool IsValidPaintShaderScalingBehavior(PaintShader::ScalingBehavior behavior) {
@@ -460,10 +468,14 @@
   ReadSimple(&ref.flags_);
   ReadSimple(&ref.end_radius_);
   ReadSimple(&ref.start_radius_);
-  ReadSimple(&ref.tx_);
-  ReadSimple(&ref.ty_);
-  if (!IsValidSkShaderTileMode(ref.tx_) || !IsValidSkShaderTileMode(ref.ty_))
+
+  int32_t tx, ty;  // See ValidateAndGetSkShaderTileMode
+  Read(&tx);
+  Read(&ty);
+  if (!ValidateAndGetSkShaderTileMode(tx, &ref.tx_) ||
+      !ValidateAndGetSkShaderTileMode(ty, &ref.ty_)) {
     SetInvalid();
+  }
   ReadSimple(&ref.fallback_color_);
   ReadSimple(&ref.scaling_behavior_);
   if (!IsValidPaintShaderScalingBehavior(ref.scaling_behavior_))
diff --git a/cc/paint/paint_op_writer.cc b/cc/paint/paint_op_writer.cc
index 72783966..492e0fbc 100644
--- a/cc/paint/paint_op_writer.cc
+++ b/cc/paint/paint_op_writer.cc
@@ -397,8 +397,10 @@
   WriteSimple(shader->flags_);
   WriteSimple(shader->end_radius_);
   WriteSimple(shader->start_radius_);
-  WriteSimple(shader->tx_);
-  WriteSimple(shader->ty_);
+  // SkShader::TileMode does not have an explicitly defined backing type, so
+  // write a consistently sized value.
+  Write(static_cast<int32_t>(shader->tx_));
+  Write(static_cast<int32_t>(shader->ty_));
   WriteSimple(shader->fallback_color_);
   WriteSimple(shader->scaling_behavior_);
   if (shader->local_matrix_) {
diff --git a/cc/trees/effect_node.h b/cc/trees/effect_node.h
index 0eab343..b184461b 100644
--- a/cc/trees/effect_node.h
+++ b/cc/trees/effect_node.h
@@ -9,8 +9,8 @@
 #include "cc/paint/filter_operations.h"
 #include "third_party/skia/include/core/SkBlendMode.h"
 #include "ui/gfx/geometry/point_f.h"
-#include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/rrect_f.h"
 
 namespace base {
 namespace trace_event {
@@ -41,7 +41,7 @@
 
   FilterOperations filters;
   FilterOperations backdrop_filters;
-  gfx::RectF backdrop_filter_bounds;
+  gfx::RRectF backdrop_filter_bounds;
   float backdrop_filter_quality;
   gfx::PointF filters_origin;
 
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
index ae1fb765..e49a92b 100644
--- a/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -311,7 +311,7 @@
   background->AddChild(green_lane);
   FilterOperations filters;
   filters.Append(FilterOperation::CreateGrayscaleFilter(.75));
-  gfx::RectF backdrop_filter_bounds;
+  gfx::RRectF backdrop_filter_bounds;
   green_lane->SetBackdropFilters(filters);
   green_lane->SetBackdropFilterBounds(backdrop_filter_bounds);
   green_lane->SetBlendMode(current_blend_mode());
diff --git a/cc/trees/layer_tree_host_pixeltest_filters.cc b/cc/trees/layer_tree_host_pixeltest_filters.cc
index 22c12b0..7843440 100644
--- a/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -19,7 +19,7 @@
 
 class LayerTreeHostFiltersPixelTest : public LayerTreePixelTest {};
 
-TEST_F(LayerTreeHostFiltersPixelTest, BackdropFilterBlur) {
+TEST_F(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRect) {
   scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
       gfx::Rect(200, 200), SK_ColorWHITE);
 
@@ -36,7 +36,7 @@
   filters.Append(FilterOperation::CreateBlurFilter(
       2.f, SkBlurImageFilter::kClamp_TileMode));
   blur->SetBackdropFilters(filters);
-  gfx::RectF backdrop_filter_bounds(gfx::SizeF(blur->bounds()));
+  gfx::RRectF backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())), 0);
   blur->SetBackdropFilterBounds(backdrop_filter_bounds);
 
 #if defined(OS_WIN) || defined(ARCH_CPU_ARM64)
@@ -59,6 +59,46 @@
                base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur.png")));
 }
 
+TEST_F(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRounded) {
+  scoped_refptr<SolidColorLayer> background =
+      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
+
+  // The green box is entirely behind a layer with backdrop blur, so it
+  // should appear blurred on its edges.
+  scoped_refptr<SolidColorLayer> green =
+      CreateSolidColorLayer(gfx::Rect(50, 50, 100, 100), kCSSGreen);
+  scoped_refptr<SolidColorLayer> blur =
+      CreateSolidColorLayer(gfx::Rect(46, 46, 108, 108), SK_ColorTRANSPARENT);
+  background->AddChild(green);
+  background->AddChild(blur);
+
+  FilterOperations filters;
+  filters.Append(FilterOperation::CreateBlurFilter(
+      2.f, SkBlurImageFilter::kClamp_TileMode));
+  blur->SetBackdropFilters(filters);
+  gfx::RRectF backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())), 14,
+                                     16, 18, 20, 22, 30, 40, 50);
+  blur->SetBackdropFilterBounds(backdrop_filter_bounds);
+
+#if defined(OS_WIN) || defined(ARCH_CPU_ARM64)
+  // Windows and ARM64 have 436 pixels off by 1: crbug.com/259915
+  float percentage_pixels_large_error = 1.09f;  // 436px / (200*200)
+  float percentage_pixels_small_error = 0.0f;
+  float average_error_allowed_in_bad_pixels = 1.f;
+  int large_error_allowed = 1;
+  int small_error_allowed = 0;
+  pixel_comparator_.reset(new FuzzyPixelComparator(
+      true,  // discard_alpha
+      percentage_pixels_large_error, percentage_pixels_small_error,
+      average_error_allowed_in_bad_pixels, large_error_allowed,
+      small_error_allowed));
+#endif
+
+  RunPixelTest(
+      PIXEL_TEST_GL, background,
+      base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur_rounded.png")));
+}
+
 TEST_F(LayerTreeHostFiltersPixelTest, BackdropFilterBlurOutsets) {
   scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
       gfx::Rect(200, 200), SK_ColorWHITE);
@@ -79,7 +119,7 @@
   filters.Append(FilterOperation::CreateBlurFilter(
       5.f, SkBlurImageFilter::kClamp_TileMode));
   blur->SetBackdropFilters(filters);
-  gfx::RectF backdrop_filter_bounds(gfx::SizeF(blur->bounds()));
+  gfx::RRectF backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())), 0);
   blur->SetBackdropFilterBounds(backdrop_filter_bounds);
 
 #if defined(OS_WIN) || defined(_MIPS_ARCH_LOONGSON) || defined(ARCH_CPU_ARM64)
@@ -148,7 +188,7 @@
       2.f, SkBlurImageFilter::kClamp_TileMode));
   blur->SetBackdropFilters(filters);
   // TODO(916311): Fix clipping for 3D transformed elements.
-  blur->SetBackdropFilterBounds(gfx::RectF());
+  blur->SetBackdropFilterBounds(gfx::RRectF());
 
 #if defined(OS_WIN) || defined(ARCH_CPU_ARM64)
 #if defined(OS_WIN)
@@ -426,7 +466,7 @@
     FilterOperations filters;
     filters.Append(FilterOperation::CreateGrayscaleFilter(1.0f));
     filter->SetBackdropFilters(filters);
-    filter->SetBackdropFilterBounds(gfx::RectF());
+    filter->SetBackdropFilterBounds(gfx::RRectF());
 
 #if defined(OS_WIN) || defined(_MIPS_ARCH_LOONGSON) || defined(ARCH_CPU_ARM64)
 #if defined(OS_WIN)
@@ -505,7 +545,7 @@
     // TODO(916311): Adding filter bounds here should work, but it clips
     // the corner of the red box.
     // gfx::RectF backdrop_filter_bounds(gfx::SizeF(filter_layer->bounds()));
-    gfx::RectF backdrop_filter_bounds;
+    gfx::RRectF backdrop_filter_bounds;
     filter_layer->SetBackdropFilterBounds(backdrop_filter_bounds);
 
     background->AddChild(filter_layer);
@@ -626,7 +666,8 @@
         FilterOperation::CreateZoomFilter(2.f /* zoom */, 0 /* inset */));
     border_edge_zoom->SetBackdropFilters(border_filters);
     gfx::RectF border_filter_bounds(gfx::SizeF(border_edge_zoom->bounds()));
-    border_edge_zoom->SetBackdropFilterBounds(border_filter_bounds);
+    border_edge_zoom->SetBackdropFilterBounds(
+        gfx::RRectF(border_filter_bounds, 0));
     root->AddChild(border_edge_zoom);
 
     // Test a zoom that extends past the edge of the screen.
@@ -637,7 +678,7 @@
         FilterOperation::CreateZoomFilter(2.f /* zoom */, 0 /* inset */));
     top_edge_zoom->SetBackdropFilters(top_filters);
     gfx::RectF top_filter_bounds(gfx::SizeF(top_edge_zoom->bounds()));
-    top_edge_zoom->SetBackdropFilterBounds(top_filter_bounds);
+    top_edge_zoom->SetBackdropFilterBounds(gfx::RRectF(top_filter_bounds, 0));
     root->AddChild(top_edge_zoom);
 
     // Test a zoom that is fully within the screen.
@@ -648,7 +689,7 @@
         FilterOperation::CreateZoomFilter(2.f /* zoom */, 0 /* inset */));
     contained_zoom->SetBackdropFilters(mid_filters);
     gfx::RectF mid_filter_bounds(gfx::SizeF(contained_zoom->bounds()));
-    contained_zoom->SetBackdropFilterBounds(mid_filter_bounds);
+    contained_zoom->SetBackdropFilterBounds(gfx::RRectF(mid_filter_bounds, 0));
     root->AddChild(contained_zoom);
 
 #if defined(OS_WIN)
@@ -1092,7 +1133,7 @@
     filters.Append(FilterOperation::CreateReferenceFilter(
         sk_make_sp<OffsetPaintFilter>(0, 80, nullptr)));
     filtered->SetBackdropFilters(filters);
-    filtered->SetBackdropFilterBounds(gfx::RectF());
+    filtered->SetBackdropFilterBounds(gfx::RRectF());
     root->AddChild(filtered);
 
     // This should appear as a grid of 4 100x100 squares which are:
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc
index 36726cc8..46807685 100644
--- a/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -297,7 +297,7 @@
 
   FilterOperations filters;
   filters.Append(FilterOperation::CreateGrayscaleFilter(1.0));
-  gfx::RectF backdrop_filter_bounds;
+  gfx::RRectF backdrop_filter_bounds;
   blur->SetBackdropFilters(filters);
   blur->SetBackdropFilterBounds(backdrop_filter_bounds);
 
@@ -759,7 +759,7 @@
   FilterOperations filters;
   filters.Append(FilterOperation::CreateGrayscaleFilter(1.0));
   picture_horizontal->SetBackdropFilters(filters);
-  gfx::RectF backdrop_filter_bounds;
+  gfx::RRectF backdrop_filter_bounds;
   picture_horizontal->SetBackdropFilterBounds(backdrop_filter_bounds);
 
   background->AddChild(picture_vertical);
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index a8765e6..25bafa2 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -758,11 +758,11 @@
   return layer->test_properties()->backdrop_filters;
 }
 
-static inline const gfx::RectF& BackdropFilterBounds(Layer* layer) {
+static inline const gfx::RRectF& BackdropFilterBounds(Layer* layer) {
   return layer->backdrop_filter_bounds();
 }
 
-static inline const gfx::RectF& BackdropFilterBounds(LayerImpl* layer) {
+static inline const gfx::RRectF& BackdropFilterBounds(LayerImpl* layer) {
   return layer->test_properties()->backdrop_filter_bounds;
 }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java
deleted file mode 100644
index 08f1a22..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java
+++ /dev/null
@@ -1,376 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.media.remote;
-
-import android.graphics.Bitmap;
-
-import org.chromium.base.Log;
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-import org.chromium.blink_public.platform.modules.remoteplayback.WebRemotePlaybackAvailability;
-import org.chromium.chrome.browser.media.remote.RemoteVideoInfo.PlayerState;
-
-/**
- * Acts as a proxy between the remotely playing video and the HTMLMediaElement.
- */
-@JNINamespace("remote_media")
-public class RemoteMediaPlayerBridge {
-    private long mStartPositionMillis;
-    private long mNativeRemoteMediaPlayerBridge;
-
-    /**
-     * The route controller for the video, null if no appropriate route controller.
-     */
-    private final MediaRouteController mRouteController;
-    private final String mOriginalSourceUrl;
-    private final String mOriginalFrameUrl;
-    private String mFrameUrl;
-    private String mSourceUrl;
-    private final String mUserAgent;
-    private Bitmap mPosterBitmap;
-    private String mCookies;
-    private boolean mPauseRequested;
-    private boolean mSeekRequested;
-    private long mSeekLocation;
-    private boolean mIsPlayable;
-    private boolean mRouteIsAvailable;
-
-    // mActive is true when the Chrome is playing, or preparing to play, this player's video
-    // remotely.
-    private boolean mActive;
-
-    private static final String TAG = "MediaFling";
-
-    private final MediaRouteController.MediaStateListener mMediaStateListener =
-            new MediaRouteController.MediaStateListener() {
-        @Override
-        public void onRouteAvailabilityChanged(boolean available) {
-            mRouteIsAvailable = available;
-            onRouteAvailabilityChange();
-        }
-
-        @Override
-        public void onRouteDialogCancelled() {
-            if (mNativeRemoteMediaPlayerBridge == 0) return;
-            nativeOnCancelledRemotePlaybackRequest(mNativeRemoteMediaPlayerBridge);
-        }
-
-        @Override
-        public void onError() {
-            if (mActive && mNativeRemoteMediaPlayerBridge != 0) {
-                nativeOnError(mNativeRemoteMediaPlayerBridge);
-            }
-        }
-
-        @Override
-        public void onSeekCompleted() {
-            mSeekRequested = false;
-            if (mActive && mNativeRemoteMediaPlayerBridge != 0) {
-                nativeOnSeekCompleted(mNativeRemoteMediaPlayerBridge);
-            }
-        }
-
-        @Override
-        public void onRouteUnselected() {
-            if (mNativeRemoteMediaPlayerBridge == 0) return;
-            nativeOnRouteUnselected(mNativeRemoteMediaPlayerBridge);
-        }
-
-        @Override
-        public void onPlaybackStateChanged(@PlayerState int newState) {
-            if (mNativeRemoteMediaPlayerBridge == 0) return;
-            if (newState == PlayerState.FINISHED || newState == PlayerState.INVALIDATED) {
-                nativeOnPlaybackFinished(mNativeRemoteMediaPlayerBridge);
-            } else if (newState == PlayerState.PLAYING) {
-                nativeOnPlaying(mNativeRemoteMediaPlayerBridge);
-            } else if (newState == PlayerState.PAUSED) {
-                mPauseRequested = false;
-                nativeOnPaused(mNativeRemoteMediaPlayerBridge);
-            }
-        }
-
-        @Override
-        public String getTitle() {
-            if (mNativeRemoteMediaPlayerBridge == 0) return null;
-            return nativeGetTitle(mNativeRemoteMediaPlayerBridge);
-        }
-
-        @Override
-        public Bitmap getPosterBitmap() {
-            return mPosterBitmap;
-        }
-
-        @Override
-        public void pauseLocal() {
-            if (mNativeRemoteMediaPlayerBridge == 0) return;
-            nativePauseLocal(mNativeRemoteMediaPlayerBridge);
-        }
-
-        @Override
-        public long getLocalPosition() {
-            if (mNativeRemoteMediaPlayerBridge == 0) return 0L;
-            return nativeGetLocalPosition(mNativeRemoteMediaPlayerBridge);
-        }
-
-        @Override
-        public void onCastStarting(String routeName) {
-            if (mNativeRemoteMediaPlayerBridge != 0) {
-                nativeOnCastStarting(mNativeRemoteMediaPlayerBridge,
-                        RemoteMediaPlayerController.instance().getCastingMessage(routeName));
-            }
-            mActive = true;
-        }
-
-        @Override
-        public void onCastStarted() {
-            if (mNativeRemoteMediaPlayerBridge != 0) {
-                nativeOnCastStarted(mNativeRemoteMediaPlayerBridge);
-            }
-        }
-
-        @Override
-        public void onCastStopping() {
-            if (mNativeRemoteMediaPlayerBridge != 0) {
-                nativeOnCastStopping(mNativeRemoteMediaPlayerBridge);
-            }
-            mActive = false;
-            // Free the poster bitmap to save memory
-            mPosterBitmap = null;
-        }
-
-        @Override
-        public String getSourceUrl() {
-            return mSourceUrl;
-        }
-
-        @Override
-        public String getCookies() {
-            return mCookies;
-        }
-
-        @Override
-        public String getFrameUrl() {
-            return mFrameUrl;
-        }
-
-        @Override
-        public long getStartPositionMillis() {
-            return mStartPositionMillis;
-        }
-
-        @Override
-        public boolean isPauseRequested() {
-            return mPauseRequested;
-        }
-
-        @Override
-        public boolean isSeekRequested() {
-            return mSeekRequested;
-        }
-
-        @Override
-        public long getSeekLocation() {
-            return mSeekLocation;
-        }
-    };
-
-    private RemoteMediaPlayerBridge(long nativeRemoteMediaPlayerBridge, String sourceUrl,
-            String frameUrl, String userAgent) {
-        Log.d(TAG, "Creating RemoteMediaPlayerBridge");
-        mNativeRemoteMediaPlayerBridge = nativeRemoteMediaPlayerBridge;
-        mOriginalSourceUrl = sourceUrl;
-        mOriginalFrameUrl = frameUrl;
-        mUserAgent = userAgent;
-        // This will get null if there isn't a mediaRouteController that can play this media.
-        mRouteController = RemoteMediaPlayerController.instance()
-                .getMediaRouteController(sourceUrl, frameUrl);
-    }
-
-    @CalledByNative
-    private static RemoteMediaPlayerBridge create(long nativeRemoteMediaPlayerBridge,
-            String sourceUrl, String frameUrl, String userAgent) {
-        return new RemoteMediaPlayerBridge(
-                nativeRemoteMediaPlayerBridge, sourceUrl, frameUrl, userAgent);
-    }
-
-    /**
-     * Called when a lower layer requests that a video be cast. This will typically be a request
-     * from Blink when the cast button is pressed on the default video controls.
-     */
-    @CalledByNative
-    private void requestRemotePlayback(long startPositionMillis) {
-        Log.d(TAG, "requestRemotePlayback at t=%d", startPositionMillis);
-        if (mRouteController == null) return;
-        // Clear out the state
-        mPauseRequested = false;
-        mSeekRequested = false;
-        mStartPositionMillis = startPositionMillis;
-        RemoteMediaPlayerController.instance().requestRemotePlayback(
-                mMediaStateListener, mRouteController);
-    }
-
-    /**
-     * Called when a lower layer requests control of a video that is being cast.
-     */
-    @CalledByNative
-    private void requestRemotePlaybackControl() {
-        Log.d(TAG, "requestRemotePlaybackControl");
-        RemoteMediaPlayerController.instance().requestRemotePlaybackControl(mMediaStateListener);
-    }
-
-    /**
-     * Called when a lower layer requests to stop casting the video.
-     */
-    @CalledByNative
-    private void requestRemotePlaybackStop() {
-        Log.d(TAG, "requestRemotePlaybackStop");
-        RemoteMediaPlayerController.instance().requestRemotePlaybackStop(mMediaStateListener);
-    }
-
-    @CalledByNative
-    private void setNativePlayer() {
-        Log.d(TAG, "setNativePlayer");
-        if (mRouteController == null) return;
-        mActive = true;
-    }
-
-    @CalledByNative
-    private void onPlayerCreated() {
-        Log.d(TAG, "onPlayerCreated");
-        if (mRouteController == null) return;
-        mRouteController.addMediaStateListener(mMediaStateListener);
-    }
-
-    @CalledByNative
-    private void onPlayerDestroyed() {
-        Log.d(TAG, "onPlayerDestroyed");
-        if (mRouteController == null) return;
-        mRouteController.removeMediaStateListener(mMediaStateListener);
-    }
-
-    /**
-     * @param bitmap The bitmap of the poster for the video, null if no poster image exists.
-     *
-     *         TODO(cimamoglu): Notify the clients (probably through MediaRouteController.Listener)
-     *        of the poster image change. This is necessary for when a web page changes the poster
-     *        while the client (i.e. only ExpandedControllerActivity for now) is active.
-     */
-    @CalledByNative
-    private void setPosterBitmap(Bitmap bitmap) {
-        if (mRouteController == null) return;
-        mPosterBitmap = bitmap;
-    }
-
-    @CalledByNative
-    protected boolean isPlaying() {
-        if (mRouteController == null) return false;
-        return mRouteController.isPlaying();
-    }
-
-    @CalledByNative
-    protected int getCurrentPosition() {
-        if (mRouteController == null) return 0;
-        return (int) mRouteController.getPosition();
-    }
-
-    @CalledByNative
-    protected int getDuration() {
-        if (mRouteController == null) return 0;
-        return (int) mRouteController.getDuration();
-    }
-
-    @CalledByNative
-    protected void release() {
-        // Remove the state change listeners. Release does mean that Chrome is no longer interested
-        // in events from the media player.
-        if (mRouteController != null) mRouteController.setMediaStateListener(null);
-        mActive = false;
-    }
-
-    @CalledByNative
-    protected void setVolume(double volume) {
-    }
-
-    @CalledByNative
-    protected void start() throws IllegalStateException {
-        mPauseRequested = false;
-        if (mRouteController != null && mRouteController.isBeingCast()) mRouteController.resume();
-    }
-
-    @CalledByNative
-    protected void pause() throws IllegalStateException {
-        if (mRouteController != null && mRouteController.isBeingCast()) {
-            mRouteController.pause();
-        } else {
-            mPauseRequested = true;
-        }
-    }
-
-    @CalledByNative
-    protected void seekTo(int msec) throws IllegalStateException {
-        if (mRouteController != null && mRouteController.isBeingCast()) {
-            mRouteController.seekTo(msec);
-        } else {
-            mSeekRequested = true;
-            mSeekLocation = msec;
-        }
-    }
-
-    private void onRouteAvailabilityChange() {
-        Log.d(TAG, "onRouteAvailabilityChange: " + mRouteIsAvailable + ", " + mIsPlayable);
-        if (mNativeRemoteMediaPlayerBridge == 0) return;
-
-        int availability = WebRemotePlaybackAvailability.DEVICE_NOT_AVAILABLE;
-        if (!mIsPlayable) {
-            availability = WebRemotePlaybackAvailability.SOURCE_NOT_COMPATIBLE;
-        } else if (mRouteIsAvailable) {
-            availability = WebRemotePlaybackAvailability.DEVICE_AVAILABLE;
-        }
-        nativeOnRouteAvailabilityChanged(mNativeRemoteMediaPlayerBridge, availability);
-    }
-
-    @CalledByNative
-    protected void destroy() {
-        Log.d(TAG, "destroy");
-        if (mRouteController != null) {
-            mRouteController.removeMediaStateListener(mMediaStateListener);
-        }
-        mNativeRemoteMediaPlayerBridge = 0;
-    }
-
-    @CalledByNative
-    private void setCookies(String cookies) {
-        if (mRouteController == null) return;
-        mCookies = cookies;
-        mRouteController.checkIfPlayableRemotely(mOriginalSourceUrl, mOriginalFrameUrl, cookies,
-                mUserAgent, new MediaRouteController.MediaValidationCallback() {
-                    @Override
-                    public void onResult(
-                            boolean isPlayable, String revisedSourceUrl, String revisedFrameUrl) {
-                        mIsPlayable = isPlayable;
-                        mSourceUrl = revisedSourceUrl;
-                        mFrameUrl = revisedFrameUrl;
-                        onRouteAvailabilityChange();
-                    }
-                });
-    }
-
-    private native void nativeOnPlaying(long nativeRemoteMediaPlayerBridge);
-    private native void nativeOnPaused(long nativeRemoteMediaPlayerBridge);
-    private native void nativeOnRouteUnselected(long nativeRemoteMediaPlayerBridge);
-    private native void nativeOnPlaybackFinished(long nativeRemoteMediaPlayerBridge);
-    private native void nativeOnRouteAvailabilityChanged(
-            long nativeRemoteMediaPlayerBridge, int availability);
-    private native void nativeOnCancelledRemotePlaybackRequest(long nativeRemoteMediaPlayerBridge);
-    private native String nativeGetTitle(long nativeRemoteMediaPlayerBridge);
-    private native void nativePauseLocal(long nativeRemoteMediaPlayerBridge);
-    private native int nativeGetLocalPosition(long nativeRemoteMediaPlayerBridge);
-    private native void nativeOnCastStarting(long nativeRemoteMediaPlayerBridge,
-            String castingMessage);
-    private native void nativeOnCastStarted(long nativeRemoteMediaPlayerBridge);
-    private native void nativeOnCastStopping(long nativeRemoteMediaPlayerBridge);
-    private native void nativeOnError(long nativeRemoteMediaPlayerBridge);
-    private native void nativeOnSeekCompleted(long nativeRemoteMediaPlayerBridge);
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java
index d8abe3f8..25379ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java
@@ -67,9 +67,6 @@
 
     static final int MINIMAL_MEDIA_IMAGE_SIZE_PX = 114;
 
-    @VisibleForTesting
-    static final int CUSTOM_MEDIA_SESSION_ACTION_STOP = MediaSessionAction.MAX_VALUE + 1;
-
     // The media artwork image resolution on high-end devices.
     private static final int HIGH_IMAGE_SIZE_PX = 512;
 
@@ -746,7 +743,7 @@
         mActionToButtonInfo.put(MediaSessionAction.PAUSE,
                 new MediaButtonInfo(R.drawable.ic_pause_white_36dp, R.string.accessibility_pause,
                         ListenerService.ACTION_PAUSE));
-        mActionToButtonInfo.put(CUSTOM_MEDIA_SESSION_ACTION_STOP,
+        mActionToButtonInfo.put(MediaSessionAction.STOP,
                 new MediaButtonInfo(R.drawable.ic_stop_white_36dp, R.string.accessibility_stop,
                         ListenerService.ACTION_STOP));
         mActionToButtonInfo.put(MediaSessionAction.PREVIOUS_TRACK,
@@ -1110,7 +1107,9 @@
         }
 
         if (mMediaNotificationInfo.supportsStop()) {
-            actions.add(CUSTOM_MEDIA_SESSION_ACTION_STOP);
+            actions.add(MediaSessionAction.STOP);
+        } else {
+            actions.remove(MediaSessionAction.STOP);
         }
 
         List<Integer> bigViewActions = computeBigViewActions(actions);
@@ -1186,7 +1185,7 @@
      */
     private List<Integer> computeBigViewActions(Set<Integer> actions) {
         // STOP cannot coexist with switch track actions and seeking actions.
-        assert !actions.contains(CUSTOM_MEDIA_SESSION_ACTION_STOP)
+        assert !actions.contains(MediaSessionAction.STOP)
                 || !(actions.contains(MediaSessionAction.PREVIOUS_TRACK)
                         && actions.contains(MediaSessionAction.NEXT_TRACK)
                         && actions.contains(MediaSessionAction.SEEK_BACKWARD)
@@ -1194,8 +1193,6 @@
         // PLAY and PAUSE cannot coexist.
         assert !actions.contains(MediaSessionAction.PLAY)
                 || !actions.contains(MediaSessionAction.PAUSE);
-        // There can't be move actions than BIG_VIEW_ACTIONS_COUNT.
-        assert actions.size() <= BIG_VIEW_ACTIONS_COUNT;
 
         int[] actionByOrder = {
                 MediaSessionAction.PREVIOUS_TRACK,
@@ -1204,7 +1201,7 @@
                 MediaSessionAction.PAUSE,
                 MediaSessionAction.SEEK_FORWARD,
                 MediaSessionAction.NEXT_TRACK,
-                CUSTOM_MEDIA_SESSION_ACTION_STOP,
+                MediaSessionAction.STOP,
         };
 
         // Sort the actions based on the expected ordering in the UI.
@@ -1213,6 +1210,10 @@
             if (actions.contains(action)) sortedActions.add(action);
         }
 
+        // There can't be move actions than BIG_VIEW_ACTIONS_COUNT. We do this check after we have
+        // sorted the actions since there may be more actions that we do not support.
+        assert sortedActions.size() <= BIG_VIEW_ACTIONS_COUNT;
+
         return sortedActions;
     }
 
@@ -1227,7 +1228,7 @@
     @VisibleForTesting
     static int[] computeCompactViewActionIndices(List<Integer> actions) {
         // STOP cannot coexist with switch track actions and seeking actions.
-        assert !actions.contains(CUSTOM_MEDIA_SESSION_ACTION_STOP)
+        assert !actions.contains(MediaSessionAction.STOP)
                 || !(actions.contains(MediaSessionAction.PREVIOUS_TRACK)
                         && actions.contains(MediaSessionAction.NEXT_TRACK)
                         && actions.contains(MediaSessionAction.SEEK_BACKWARD)
@@ -1244,12 +1245,12 @@
             return actionsArray;
         }
 
-        if (actions.contains(CUSTOM_MEDIA_SESSION_ACTION_STOP)) {
+        if (actions.contains(MediaSessionAction.STOP)) {
             List<Integer> compactActions = new ArrayList<>();
             if (actions.contains(MediaSessionAction.PLAY)) {
                 compactActions.add(actions.indexOf(MediaSessionAction.PLAY));
             }
-            compactActions.add(actions.indexOf(CUSTOM_MEDIA_SESSION_ACTION_STOP));
+            compactActions.add(actions.indexOf(MediaSessionAction.STOP));
             return CollectionUtil.integerListToIntArray(compactActions);
         }
 
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 36cbf83b..e3f220c 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -907,7 +907,6 @@
   "java/src/org/chromium/chrome/browser/media/remote/MediaUrlResolver.java",
   "java/src/org/chromium/chrome/browser/media/remote/PositionExtrapolator.java",
   "java/src/org/chromium/chrome/browser/media/remote/RecordCastAction.java",
-  "java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java",
   "java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java",
   "java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerWrapper.java",
   "java/src/org/chromium/chrome/browser/media/remote/RemoteVideoInfo.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
index f229514..d5c59aa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/profiling_host/ProfilingProcessHostAndroidTest.java
@@ -43,22 +43,36 @@
     public void
     testModeBrowser() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(
-                shim.runTestForMode("browser", false, "native-include-thread-names", false, false));
+        Assert.assertTrue(shim.runTestForMode(
+                "browser", false, "native-include-thread-names", true, false, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamic() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "native", false, false));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "native", true, false, false));
+    }
+
+    @Test
+    @MediumTest
+    public void testModeBrowserDynamicNonStreaming() throws Exception {
+        HeapProfilingTestShim shim = new HeapProfilingTestShim();
+        Assert.assertTrue(shim.runTestForMode("browser", true, "native", false, false, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudo() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", false, false));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false, false));
+    }
+
+    @Test
+    @MediumTest
+    public void testModeBrowserDynamicPseudoNonStreaming() throws Exception {
+        HeapProfilingTestShim shim = new HeapProfilingTestShim();
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", false, false, false));
     }
 
     // Non-browser processes must be profiled with a command line flag, since
@@ -73,7 +87,8 @@
     Add({"memlog=all-renderers", "memlog-stack-mode=pseudo", "memlog-sampling-rate=1"})
     public void testModeRendererPseudo() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("all-renderers", false, "pseudo", false, false));
+        Assert.assertTrue(
+                shim.runTestForMode("all-renderers", false, "pseudo", true, false, false));
     }
 
     @Test
@@ -81,27 +96,28 @@
     @CommandLineFlags.Add({"memlog=gpu", "memlog-stack-mode=pseudo", "memlog-sampling-rate=1"})
     public void testModeGpuPseudo() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("gpu", false, "native", false, false));
+        Assert.assertTrue(shim.runTestForMode("gpu", false, "native", true, false, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudoSampleEverything() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true, true));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserDynamicPseudoSamplePartial() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, false));
+        Assert.assertTrue(shim.runTestForMode("browser", true, "pseudo", true, true, false));
     }
 
     @Test
     @MediumTest
     public void testModeBrowserAndAllUtility() throws Exception {
         HeapProfilingTestShim shim = new HeapProfilingTestShim();
-        Assert.assertTrue(shim.runTestForMode("utility-and-browser", true, "pseudo", true, false));
+        Assert.assertTrue(
+                shim.runTestForMode("utility-and-browser", true, "pseudo", true, true, false));
     }
 }
diff --git a/chrome/app/android/chrome_main_delegate_android.cc b/chrome/app/android/chrome_main_delegate_android.cc
index 213c8d37..c76d611b 100644
--- a/chrome/app/android/chrome_main_delegate_android.cc
+++ b/chrome/app/android/chrome_main_delegate_android.cc
@@ -13,7 +13,6 @@
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/android/chrome_startup_flags.h"
 #include "chrome/browser/android/metrics/uma_utils.h"
-#include "chrome/browser/media/android/remote/remote_media_player_manager.h"
 #include "components/policy/core/browser/android/android_combined_policy_provider.h"
 #include "components/safe_browsing/android/safe_browsing_api_handler.h"
 #include "components/safe_browsing/android/safe_browsing_api_handler_bridge.h"
@@ -23,14 +22,6 @@
 
 using safe_browsing::SafeBrowsingApiHandler;
 
-namespace {
-
-content::BrowserMediaPlayerManager* CreateRemoteMediaPlayerManager(
-    content::RenderFrameHost* render_frame_host) {
-  return new remote_media::RemoteMediaPlayerManager(render_frame_host);
-}
-
-} // namespace
 
 // ChromeMainDelegateAndroid is created when the library is loaded. It is always
 // done in the process's main Java thread. But for non browser process, e.g.
@@ -48,8 +39,6 @@
 
   policy::android::AndroidCombinedPolicyProvider::SetShouldWaitForPolicy(true);
   SetChromeSpecificCommandLineFlags();
-  content::BrowserMediaPlayerManager::RegisterFactory(
-      &CreateRemoteMediaPlayerManager);
 
   return ChromeMainDelegate::BasicStartupComplete(exit_code);
 }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 540dbee..970fcd4 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2529,10 +2529,6 @@
       "media/android/remote/flinging_controller_bridge.cc",
       "media/android/remote/flinging_controller_bridge.h",
       "media/android/remote/record_cast_action.cc",
-      "media/android/remote/remote_media_player_bridge.cc",
-      "media/android/remote/remote_media_player_bridge.h",
-      "media/android/remote/remote_media_player_manager.cc",
-      "media/android/remote/remote_media_player_manager.h",
       "media/android/router/media_router_android.cc",
       "media/android/router/media_router_android.h",
       "media/android/router/media_router_android_bridge.cc",
@@ -4914,7 +4910,6 @@
       "../android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java",
       "../android/java/src/org/chromium/chrome/browser/locale/LocaleTemplateUrlLoader.java",
       "../android/java/src/org/chromium/chrome/browser/media/remote/RecordCastAction.java",
-      "../android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java",
       "../android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java",
       "../android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterDialogController.java",
       "../android/java/src/org/chromium/chrome/browser/media/router/FlingingControllerBridge.java",
diff --git a/chrome/browser/browsing_data/counters/site_settings_counter.cc b/chrome/browser/browsing_data/counters/site_settings_counter.cc
index 3bdfa0a..15bac40 100644
--- a/chrome/browser/browsing_data/counters/site_settings_counter.cc
+++ b/chrome/browser/browsing_data/counters/site_settings_counter.cc
@@ -49,31 +49,44 @@
   base::Time period_start = GetPeriodStart();
   base::Time period_end = GetPeriodEnd();
 
+  auto iterate_content_settings_list =
+      [&](ContentSettingsType content_type,
+          const ContentSettingsForOneType& content_settings_list) {
+        for (const auto& content_setting : content_settings_list) {
+          // TODO(crbug.com/762560): Check the conceptual SettingSource instead
+          // of ContentSettingPatternSource.source
+          if (content_setting.source == "preference" ||
+              content_setting.source == "notification_android" ||
+              content_setting.source == "ephemeral") {
+            base::Time last_modified = map_->GetSettingLastModifiedDate(
+                content_setting.primary_pattern,
+                content_setting.secondary_pattern, content_type);
+            if (last_modified >= period_start && last_modified < period_end) {
+              if (content_setting.primary_pattern.GetHost().empty())
+                empty_host_pattern++;
+              else
+                hosts.insert(content_setting.primary_pattern.GetHost());
+            }
+          }
+        }
+      };
+
   auto* registry = content_settings::ContentSettingsRegistry::GetInstance();
   for (const content_settings::ContentSettingsInfo* info : *registry) {
     ContentSettingsType type = info->website_settings_info()->type();
     ContentSettingsForOneType content_settings_list;
     map_->GetSettingsForOneType(type, content_settings::ResourceIdentifier(),
                                 &content_settings_list);
-    for (const auto& content_setting : content_settings_list) {
-      // TODO(crbug.com/762560): Check the conceptual SettingSource instead of
-      // ContentSettingPatternSource.source
-      if (content_setting.source == "preference" ||
-          content_setting.source == "notification_android" ||
-          content_setting.source == "ephemeral") {
-        base::Time last_modified = map_->GetSettingLastModifiedDate(
-            content_setting.primary_pattern, content_setting.secondary_pattern,
-            type);
-        if (last_modified >= period_start && last_modified < period_end) {
-          if (content_setting.primary_pattern.GetHost().empty())
-            empty_host_pattern++;
-          else
-            hosts.insert(content_setting.primary_pattern.GetHost());
-        }
-      }
-    }
+    iterate_content_settings_list(type, content_settings_list);
   }
 
+  ContentSettingsForOneType content_settings_list_for_usb_chooser;
+  map_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA,
+                              content_settings::ResourceIdentifier(),
+                              &content_settings_list_for_usb_chooser);
+  iterate_content_settings_list(CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA,
+                                content_settings_list_for_usb_chooser);
+
 #if !defined(OS_ANDROID)
   for (const auto& zoom_level : zoom_map_->GetAllZoomLevels()) {
     // zoom_level with non-empty scheme are only used for some internal
diff --git a/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc b/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc
index e872118..8f3e90e 100644
--- a/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc
+++ b/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc
@@ -157,6 +157,17 @@
   EXPECT_EQ(1, GetResult());
 }
 
+// Tests that the counter counts WebUSB settings
+TEST_F(SiteSettingsCounterTest, CountWebUsbSettings) {
+  map()->SetWebsiteSettingDefaultScope(
+      GURL("http://www.google.com"), GURL("http://www.google.com"),
+      CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA, std::string(),
+      std::make_unique<base::DictionaryValue>());
+
+  counter()->Restart();
+  EXPECT_EQ(1, GetResult());
+}
+
 // Tests that the counter counts settings with the same pattern only
 // once.
 TEST_F(SiteSettingsCounterTest, OnlyCountPatternOnce) {
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index eec7001..bf626de 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -659,11 +659,15 @@
 }
 
 void ExistingUserController::OnSigninScreenReady() {
+  // Used to debug crbug.com/902315. Feel free to remove after that is fixed.
+  VLOG(1) << "OnSigninScreenReady";
   auto_launch_ready_ = true;
   StartAutoLoginTimer();
 }
 
 void ExistingUserController::OnGaiaScreenReady() {
+  // Used to debug crbug.com/902315. Feel free to remove after that is fixed.
+  VLOG(1) << "OnGaiaScreenReady";
   auto_launch_ready_ = true;
   StartAutoLoginTimer();
 }
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index a83cf78..63453c8 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -718,6 +718,8 @@
 void ScreenLocker::OnAuthScanDone(
     device::mojom::ScanResult scan_result,
     const base::flat_map<std::string, std::vector<std::string>>& matches) {
+  RefreshPinAndFingerprintTimeout();
+
   VLOG(1) << "Receive fingerprint auth scan result. scan_result="
           << scan_result;
   unlock_attempt_type_ = AUTH_FINGERPRINT;
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_common.cc b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
index 21fd842..8e42ed59 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_common.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
@@ -182,8 +182,12 @@
 }
 
 void LoginDisplayHostCommon::OnGaiaScreenReady() {
-  if (GetExistingUserController())
+  if (GetExistingUserController()) {
     GetExistingUserController()->OnGaiaScreenReady();
+  } else {
+    // Used to debug crbug.com/902315. Feel free to remove after that is fixed.
+    LOG(ERROR) << "OnGaiaScreenReady: there is no existing user controller";
+  }
 }
 
 void LoginDisplayHostCommon::SetDisplayEmail(const std::string& email) {
diff --git a/chrome/browser/chromeos/login/ui/login_display_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_mojo.cc
index 90d319e..89f719d 100644
--- a/chrome/browser/chromeos/login/ui/login_display_mojo.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_mojo.cc
@@ -91,7 +91,8 @@
 }
 
 void LoginDisplayMojo::OnPreferencesChanged() {
-  NOTIMPLEMENTED();
+  if (webui_handler_)
+    webui_handler_->OnPreferencesChanged();
 }
 
 void LoginDisplayMojo::SetUIEnabled(bool is_enabled) {
@@ -191,7 +192,8 @@
 }
 
 void LoginDisplayMojo::OnSigninScreenReady() {
-  NOTIMPLEMENTED();
+  if (delegate_)
+    delegate_->OnSigninScreenReady();
 }
 
 void LoginDisplayMojo::ShowEnterpriseEnrollmentScreen() {
diff --git a/chrome/browser/conflicts/incompatible_applications_updater_win.cc b/chrome/browser/conflicts/incompatible_applications_updater_win.cc
index 9741add..d7b95eb4 100644
--- a/chrome/browser/conflicts/incompatible_applications_updater_win.cc
+++ b/chrome/browser/conflicts/incompatible_applications_updater_win.cc
@@ -283,15 +283,14 @@
     const ModuleInfoData& module_data) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  // The module id is always positive.
-  if (module_key.module_id + 1 > module_warning_decisions_.size())
-    module_warning_decisions_.resize(module_key.module_id + 1);
+  // This is meant to create the element in the map if it doesn't exist yet.
+  ModuleWarningDecision& warning_decision =
+      module_warning_decisions_[module_key];
 
   // Only consider loaded modules.
   if ((module_data.module_properties & ModuleInfoData::kPropertyLoadedModule) ==
       0) {
-    module_warning_decisions_[module_key.module_id] =
-        ModuleWarningDecision::kNotLoaded;
+    warning_decision = ModuleWarningDecision::kNotLoaded;
     return;
   }
 
@@ -303,8 +302,7 @@
   if (exe_certificate_info_.type != CertificateInfo::Type::NO_CERTIFICATE &&
       exe_certificate_info_.subject ==
           module_data.inspection_result->certificate_info.subject) {
-    module_warning_decisions_[module_key.module_id] =
-        ModuleWarningDecision::kAllowedSameCertificate;
+    warning_decision = ModuleWarningDecision::kAllowedSameCertificate;
     return;
   }
 
@@ -312,8 +310,7 @@
   // attempt is made to check the validity of the certificate.
   if (IsMicrosoftModule(
           module_data.inspection_result->certificate_info.subject)) {
-    module_warning_decisions_[module_key.module_id] =
-        ModuleWarningDecision::kAllowedMicrosoft;
+    warning_decision = ModuleWarningDecision::kAllowedMicrosoft;
     return;
   }
 
@@ -328,15 +325,13 @@
   base::FilePath exe_path;
   if (base::PathService::Get(base::DIR_EXE, &exe_path) &&
       exe_path.DirName().IsParent(module_key.module_path)) {
-    module_warning_decisions_[module_key.module_id] =
-        ModuleWarningDecision::kAllowedSameDirectory;
+    warning_decision = ModuleWarningDecision::kAllowedSameDirectory;
     return;
   }
 
   // Skip modules whitelisted by the Module List component.
   if (module_list_filter_->IsWhitelisted(module_key, module_data)) {
-    module_warning_decisions_[module_key.module_id] =
-        ModuleWarningDecision::kAllowedWhitelisted;
+    warning_decision = ModuleWarningDecision::kAllowedWhitelisted;
     return;
   }
 
@@ -344,14 +339,12 @@
   // it is whitelisted, not because it's a shell extension. Thus, check for the
   // module type after.
   if (module_data.module_properties & ModuleInfoData::kPropertyShellExtension) {
-    module_warning_decisions_[module_key.module_id] =
-        ModuleWarningDecision::kAllowedShellExtension;
+    warning_decision = ModuleWarningDecision::kAllowedShellExtension;
     return;
   }
 
   if (module_data.module_properties & ModuleInfoData::kPropertyIme) {
-    module_warning_decisions_[module_key.module_id] =
-        ModuleWarningDecision::kAllowedIME;
+    warning_decision = ModuleWarningDecision::kAllowedIME;
     return;
   }
 
@@ -359,8 +352,7 @@
   // is going to be blocked on the next Chrome launch.
   if (module_data.module_properties &
       ModuleInfoData::kPropertyAddedToBlacklist) {
-    module_warning_decisions_[module_key.module_id] =
-        ModuleWarningDecision::kAddedToBlacklist;
+    warning_decision = ModuleWarningDecision::kAddedToBlacklist;
     return;
   }
 
@@ -371,13 +363,11 @@
       module_key.module_path, &associated_applications);
   UMA_HISTOGRAM_BOOLEAN("ThirdPartyModules.Uninstallable", tied_to_app);
   if (!tied_to_app) {
-    module_warning_decisions_[module_key.module_id] =
-        ModuleWarningDecision::kNoTiedApplication;
+    warning_decision = ModuleWarningDecision::kNoTiedApplication;
     return;
   }
 
-  module_warning_decisions_[module_key.module_id] =
-      ModuleWarningDecision::kIncompatible;
+  warning_decision = ModuleWarningDecision::kIncompatible;
 
   std::unique_ptr<chrome::conflicts::BlacklistAction> blacklist_action =
       module_list_filter_->IsBlacklisted(module_key, module_data);
@@ -437,9 +427,8 @@
 
 IncompatibleApplicationsUpdater::ModuleWarningDecision
 IncompatibleApplicationsUpdater::GetModuleWarningDecision(
-    ModuleInfoKey module_key) const {
-  DCHECK(module_warning_decisions_.size() > module_key.module_id);
-  DCHECK_NE(module_warning_decisions_[module_key.module_id],
-            ModuleWarningDecision::kUnknown);
-  return module_warning_decisions_[module_key.module_id];
+    const ModuleInfoKey& module_key) const {
+  auto it = module_warning_decisions_.find(module_key);
+  DCHECK(it != module_warning_decisions_.end());
+  return it->second;
 }
diff --git a/chrome/browser/conflicts/incompatible_applications_updater_win.h b/chrome/browser/conflicts/incompatible_applications_updater_win.h
index d786dd1..0cb9b3e4 100644
--- a/chrome/browser/conflicts/incompatible_applications_updater_win.h
+++ b/chrome/browser/conflicts/incompatible_applications_updater_win.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/conflicts/installed_applications_win.h"
@@ -32,9 +33,7 @@
   // ModuleBlacklistCacheUpdater. This is done so that it is easier to keep the
   // 2 features separate, as they can be independently enabled/disabled.
   enum ModuleWarningDecision {
-    // Explicitly defined as zero so it is the default value when a
-    // ModuleWarningDecision
-    // variable is value-initialized (std::vector::resize()).
+    // No decision was taken yet for the module.
     kUnknown = 0,
     // A shell extension or IME that is not loaded in the process yet.
     kNotLoaded,
@@ -110,7 +109,7 @@
 
   // Returns the warning decision for a module.
   ModuleWarningDecision GetModuleWarningDecision(
-      ModuleInfoKey module_key) const;
+      const ModuleInfoKey& module_key) const;
 
  private:
   ModuleDatabaseEventSource* const module_database_event_source_;
@@ -125,9 +124,9 @@
   // Becomes false on the first call to OnModuleDatabaseIdle.
   bool before_first_idle_ = true;
 
-  // Holds the warning decision for all known modules. The index is the module
-  // id.
-  std::vector<ModuleWarningDecision> module_warning_decisions_;
+  // Holds the warning decision for all known modules.
+  base::flat_map<ModuleInfoKey, ModuleWarningDecision>
+      module_warning_decisions_;
 
   DISALLOW_COPY_AND_ASSIGN(IncompatibleApplicationsUpdater);
 };
diff --git a/chrome/browser/conflicts/incompatible_applications_updater_win_unittest.cc b/chrome/browser/conflicts/incompatible_applications_updater_win_unittest.cc
index ddc7391b..ce364cc 100644
--- a/chrome/browser/conflicts/incompatible_applications_updater_win_unittest.cc
+++ b/chrome/browser/conflicts/incompatible_applications_updater_win_unittest.cc
@@ -186,7 +186,7 @@
 
   // Simulate some arbitrary module loading into the process.
   incompatible_applications_updater->OnNewModuleFound(
-      ModuleInfoKey(dll1_, 0, 0, 0), CreateLoadedModuleInfoData());
+      ModuleInfoKey(dll1_, 0, 0), CreateLoadedModuleInfoData());
   incompatible_applications_updater->OnModuleDatabaseIdle();
 
   EXPECT_FALSE(IncompatibleApplicationsUpdater::HasCachedApplications());
@@ -198,7 +198,7 @@
       CreateIncompatibleApplicationsUpdater();
 
   // Simulate the module loading into the process.
-  ModuleInfoKey module_key(dll1_, 0, 0, 0);
+  ModuleInfoKey module_key(dll1_, 0, 0);
   incompatible_applications_updater->OnNewModuleFound(
       module_key, CreateLoadedModuleInfoData());
   incompatible_applications_updater->OnModuleDatabaseIdle();
@@ -219,7 +219,7 @@
       CreateIncompatibleApplicationsUpdater();
 
   // Simulate the module loading into the process.
-  ModuleInfoKey module_key(dll1_, 0, 0, 0);
+  ModuleInfoKey module_key(dll1_, 0, 0);
   incompatible_applications_updater->OnNewModuleFound(
       module_key, CreateLoadedModuleInfoData());
   incompatible_applications_updater->OnModuleDatabaseIdle();
@@ -242,7 +242,7 @@
       CreateIncompatibleApplicationsUpdater();
 
   // Simulate the module loading into the process.
-  ModuleInfoKey module_key(dll1_, 0, 0, 0);
+  ModuleInfoKey module_key(dll1_, 0, 0);
   incompatible_applications_updater->OnNewModuleFound(
       module_key, CreateLoadedModuleInfoData());
   incompatible_applications_updater->OnModuleDatabaseIdle();
@@ -265,13 +265,13 @@
       CreateIncompatibleApplicationsUpdater();
 
   // Simulate the module loading into the process.
-  ModuleInfoKey module_key1(dll1_, 0, 0, 0);
+  ModuleInfoKey module_key1(dll1_, 0, 0);
   incompatible_applications_updater->OnNewModuleFound(
       module_key1, CreateLoadedModuleInfoData());
   incompatible_applications_updater->OnModuleDatabaseIdle();
 
   // Add an additional module.
-  ModuleInfoKey module_key2(dll2_, 0, 0, 1);
+  ModuleInfoKey module_key2(dll2_, 0, 0);
   incompatible_applications_updater->OnNewModuleFound(
       module_key2, CreateLoadedModuleInfoData());
   incompatible_applications_updater->OnModuleDatabaseIdle();
@@ -302,7 +302,7 @@
 
   // Simulate the module loading into the process.
   incompatible_applications_updater->OnNewModuleFound(
-      ModuleInfoKey(dll1_, 0, 0, 0), CreateLoadedModuleInfoData());
+      ModuleInfoKey(dll1_, 0, 0), CreateLoadedModuleInfoData());
   incompatible_applications_updater->OnModuleDatabaseIdle();
 
   EXPECT_TRUE(IncompatibleApplicationsUpdater::HasCachedApplications());
@@ -323,9 +323,9 @@
 
   // Simulate the modules loading into the process.
   incompatible_applications_updater->OnNewModuleFound(
-      ModuleInfoKey(dll1_, 0, 0, 0), CreateLoadedModuleInfoData());
+      ModuleInfoKey(dll1_, 0, 0), CreateLoadedModuleInfoData());
   incompatible_applications_updater->OnNewModuleFound(
-      ModuleInfoKey(dll2_, 0, 0, 1), CreateLoadedModuleInfoData());
+      ModuleInfoKey(dll2_, 0, 0), CreateLoadedModuleInfoData());
   incompatible_applications_updater->OnModuleDatabaseIdle();
 
   EXPECT_TRUE(IncompatibleApplicationsUpdater::HasCachedApplications());
@@ -342,7 +342,7 @@
       CreateIncompatibleApplicationsUpdater();
 
   // Simulate the module loading into the process.
-  ModuleInfoKey module_key(dll1_, 0, 0, 0);
+  ModuleInfoKey module_key(dll1_, 0, 0);
   ModuleInfoData module_data;
   module_data.inspection_result = base::make_optional<ModuleInspectionResult>();
   incompatible_applications_updater->OnNewModuleFound(module_key, module_data);
@@ -366,7 +366,7 @@
       CreateIncompatibleApplicationsUpdater();
 
   // Simulate the module loading into the process.
-  ModuleInfoKey module_key(dll1_, 0, 0, 0);
+  ModuleInfoKey module_key(dll1_, 0, 0);
   incompatible_applications_updater->OnNewModuleFound(
       module_key, CreateSignedLoadedModuleInfoData());
   incompatible_applications_updater->OnModuleDatabaseIdle();
@@ -392,11 +392,11 @@
       CreateIncompatibleApplicationsUpdater();
 
   // Set the respective bit for registered modules.
-  ModuleInfoKey module_key1(dll1_, 0, 0, 0);
+  ModuleInfoKey module_key1(dll1_, 0, 0);
   auto module_data1 = CreateLoadedModuleInfoData();
   module_data1.module_properties |= ModuleInfoData::kPropertyShellExtension;
 
-  ModuleInfoKey module_key2(dll2_, 0, 0, 1);
+  ModuleInfoKey module_key2(dll2_, 0, 0);
   auto module_data2 = CreateLoadedModuleInfoData();
   module_data2.module_properties |= ModuleInfoData::kPropertyIme;
 
@@ -433,7 +433,7 @@
 
   // Simulate the module loading into the process.
   incompatible_applications_updater->OnNewModuleFound(
-      ModuleInfoKey(dll1_, 0, 0, 0), module_data);
+      ModuleInfoKey(dll1_, 0, 0), module_data);
   incompatible_applications_updater->OnModuleDatabaseIdle();
 
   EXPECT_FALSE(IncompatibleApplicationsUpdater::HasCachedApplications());
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc b/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
index 6642ceae..f47b7e49 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
@@ -233,16 +233,14 @@
     const ModuleInfoData& module_data) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  // The module id is always positive.
-  if (module_key.module_id + 1 > module_blocking_state_.size())
-    module_blocking_state_.resize(module_key.module_id + 1);
-
   // Create a "packed list module" entry for this module.
   third_party_dlls::PackedListModule packed_list_module;
   PopulatePackedListModule(module_key, &packed_list_module);
 
+  // This is meant to create the element in the map if it doesn't exist yet.
+  ModuleBlockingState& blocking_state = module_blocking_states_[module_key];
+
   // Determine if the module was in the initial blacklist cache.
-  auto& blocking_state = module_blocking_state_[module_key.module_id];
   blocking_state.was_in_blacklist_cache =
       std::binary_search(std::begin(initial_blacklisted_modules_),
                          std::end(initial_blacklisted_modules_),
@@ -301,12 +299,10 @@
 
 const ModuleBlacklistCacheUpdater::ModuleBlockingState&
 ModuleBlacklistCacheUpdater::GetModuleBlockingState(
-    ModuleInfoKey module_key) const {
-  DCHECK_GT(module_blocking_state_.size(),
-            static_cast<size_t>(module_key.module_id));
-  DCHECK_NE(module_blocking_state_[module_key.module_id].blocking_decision,
-            ModuleBlockingDecision::kUnknown);
-  return module_blocking_state_[module_key.module_id];
+    const ModuleInfoKey& module_key) const {
+  auto it = module_blocking_states_.find(module_key);
+  DCHECK(it != module_blocking_states_.end());
+  return it->second;
 }
 
 void ModuleBlacklistCacheUpdater::OnTimerExpired() {
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win.h b/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
index 97bf00e..273c497 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/containers/flat_map.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/md5.h"
@@ -76,10 +77,8 @@
   // IncompatibleApplicationsUpdater. This is done so that it is easier to keep
   // the 2 features separate, as they can be independently enabled/disabled.
   enum class ModuleBlockingDecision {
-    // Explicitly defined as zero so it is the default value when a
-    // ModuleBlockingDecision variable is value-initialized
-    // (std::vector::resize()).
-    kUnknown = 0,
+    // No decision was taken yet for the module.
+    kUnknown,
 
     // Detailed reasons why modules will be allowed to load in subsequent
     // startups.
@@ -122,20 +121,20 @@
   struct ModuleBlockingState {
     // Whether or not the module was in the blacklist cache that existed at
     // startup.
-    bool was_in_blacklist_cache;
+    bool was_in_blacklist_cache = false;
 
     // Whether or not the module was ever actively blocked from loading during
     // this session.
-    bool was_blocked;
+    bool was_blocked = false;
 
     // Whether or not the module ever loaded during this session. Usually this
     // means that the module is currently loaded, but it's possible for DLLs to
     // subsequently be unloaded at runtime.
-    bool was_loaded;
+    bool was_loaded = false;
 
     // The current blocking decision. This is synced to the cache and will be
     // applied at the next startup.
-    ModuleBlockingDecision blocking_decision;
+    ModuleBlockingDecision blocking_decision = ModuleBlockingDecision::kUnknown;
   };
 
   struct CacheUpdateResult {
@@ -184,7 +183,7 @@
 
   // Returns the blocking decision for a module.
   const ModuleBlockingState& GetModuleBlockingState(
-      ModuleInfoKey module_key) const;
+      const ModuleInfoKey& module_key) const;
 
  private:
   // The state of the module with respect to the ModuleList.
@@ -242,9 +241,8 @@
   // OnModuleDatabaseIdle() is never called again.
   base::OneShotTimer timer_;
 
-  // Holds the blocking state for all known modules. The index is the module
-  // id.
-  std::vector<ModuleBlockingState> module_blocking_state_;
+  // Holds the blocking state for all known modules.
+  base::flat_map<ModuleInfoKey, ModuleBlockingState> module_blocking_states_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
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 4899d14..b703797 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
@@ -202,7 +202,7 @@
   auto module_blacklist_cache_updater = CreateModuleBlacklistCacheUpdater();
 
   // Simulate some arbitrary module loading into the process.
-  ModuleInfoKey module_key(dll1_, 0, 0, 0);
+  ModuleInfoKey module_key(dll1_, 0, 0);
   module_blacklist_cache_updater->OnNewModuleFound(
       module_key, CreateLoadedModuleInfoData());
   module_blacklist_cache_updater->OnModuleDatabaseIdle();
@@ -245,7 +245,7 @@
   uint32_t time_date_stamp =
       kernel32_image.GetNTHeaders()->FileHeader.TimeDateStamp;
 
-  ModuleInfoKey module_key(module_path, module_size, time_date_stamp, 0);
+  ModuleInfoKey module_key(module_path, module_size, time_date_stamp);
   ModuleInfoData module_data = CreateLoadedModuleInfoData();
   module_data.inspection_result = InspectModule(module_key.module_path);
 
@@ -279,7 +279,7 @@
   auto module_blacklist_cache_updater = CreateModuleBlacklistCacheUpdater();
 
   // Simulate the module loading into the process.
-  ModuleInfoKey module_key(dll1_, 0, 0, 0);
+  ModuleInfoKey module_key(dll1_, 0, 0);
   module_blacklist_cache_updater->OnNewModuleFound(
       module_key, CreateSignedLoadedModuleInfoData());
   module_blacklist_cache_updater->OnModuleDatabaseIdle();
@@ -311,11 +311,11 @@
   auto module_blacklist_cache_updater = CreateModuleBlacklistCacheUpdater();
 
   // Set the respective bit for registered modules.
-  ModuleInfoKey module_key1(dll1_, 123u, 456u, 0);
+  ModuleInfoKey module_key1(dll1_, 123u, 456u);
   ModuleInfoData module_data1 = CreateLoadedModuleInfoData();
   module_data1.module_properties |= ModuleInfoData::kPropertyIme;
 
-  ModuleInfoKey module_key2(dll2_, 456u, 789u, 1);
+  ModuleInfoKey module_key2(dll2_, 456u, 789u);
   ModuleInfoData module_data2 = CreateLoadedModuleInfoData();
   module_data2.module_properties |= ModuleInfoData::kPropertyShellExtension;
 
diff --git a/chrome/browser/conflicts/module_database_win.cc b/chrome/browser/conflicts/module_database_win.cc
index 5ca7132..14d24af3 100644
--- a/chrome/browser/conflicts/module_database_win.cc
+++ b/chrome/browser/conflicts/module_database_win.cc
@@ -219,7 +219,7 @@
                                               uint32_t module_size,
                                               uint32_t module_time_date_stamp) {
   auto iter = modules_.find(
-      ModuleInfoKey(module_path, module_size, module_time_date_stamp, 0));
+      ModuleInfoKey(module_path, module_size, module_time_date_stamp));
 
   // Only known modules should be added to the blacklist.
   DCHECK(iter != modules_.end());
@@ -303,8 +303,7 @@
     ModuleDatabase::ModuleInfo** module_info) {
   auto result = modules_.emplace(
       std::piecewise_construct,
-      std::forward_as_tuple(module_path, module_size, module_time_date_stamp,
-                            modules_.size()),
+      std::forward_as_tuple(module_path, module_size, module_time_date_stamp),
       std::forward_as_tuple());
 
   // New modules must be inspected.
diff --git a/chrome/browser/conflicts/module_info_win.cc b/chrome/browser/conflicts/module_info_win.cc
index 0b5fcd9..26615724 100644
--- a/chrome/browser/conflicts/module_info_win.cc
+++ b/chrome/browser/conflicts/module_info_win.cc
@@ -59,12 +59,10 @@
 
 ModuleInfoKey::ModuleInfoKey(const base::FilePath& module_path,
                              uint32_t module_size,
-                             uint32_t module_time_date_stamp,
-                             uint32_t module_id)
+                             uint32_t module_time_date_stamp)
     : module_path(module_path),
       module_size(module_size),
-      module_time_date_stamp(module_time_date_stamp),
-      module_id(module_id) {}
+      module_time_date_stamp(module_time_date_stamp) {}
 
 bool ModuleInfoKey::operator<(const ModuleInfoKey& mik) const {
   // The key consists of the triplet of
diff --git a/chrome/browser/conflicts/module_info_win.h b/chrome/browser/conflicts/module_info_win.h
index 9638392..146cbae 100644
--- a/chrome/browser/conflicts/module_info_win.h
+++ b/chrome/browser/conflicts/module_info_win.h
@@ -15,16 +15,12 @@
 // ModuleInfoKey and ModuleInfoData are used in pair by the ModuleDatabase to
 // maintain information about a module, usually in a std::map.
 
-// Used by the ModuleDatabase as a unique identifier for a module.
-using ModuleId = uint32_t;
-
 // This is the constant portion of the module information, and is used to
 // uniquely identify one.
 struct ModuleInfoKey {
   ModuleInfoKey(const base::FilePath& module_path,
                 uint32_t module_size,
-                uint32_t module_time_date_stamp,
-                uint32_t module_id);
+                uint32_t module_time_date_stamp);
 
   // Less-than operator allowing this object to be used in std::map.
   bool operator<(const ModuleInfoKey& mi) const;
@@ -39,12 +35,6 @@
   // The module time date stamp. Part of the key for a ModuleInfo. Taken from
   // TimeDateStamp from the module's IMAGE_FILE_HEADER.
   uint32_t module_time_date_stamp;
-
-  // The ID of this module. This is a strictly incrementing value, and is used
-  // by the ModuleDatabase to tie a module to the list of running processes in
-  // which it is found. It is not part of the key for the module, but it is
-  // immutable. This is simply the index of the module in the insertion order.
-  ModuleId module_id;
 };
 
 // Holds more detailed information about a given module. Because all of this
diff --git a/chrome/browser/conflicts/module_info_win_unittest.cc b/chrome/browser/conflicts/module_info_win_unittest.cc
index ec7a4f7..d1215958 100644
--- a/chrome/browser/conflicts/module_info_win_unittest.cc
+++ b/chrome/browser/conflicts/module_info_win_unittest.cc
@@ -46,7 +46,7 @@
 
 TEST(ModuleInfoTest, GenerateCodeId) {
   static const char kExpected[] = "00000BADf00d";
-  ModuleInfoKey module_key = {base::FilePath(), 0xf00d, 0xbad, 1};
+  ModuleInfoKey module_key = {base::FilePath(), 0xf00d, 0xbad};
   EXPECT_STREQ(kExpected, GenerateCodeId(module_key).c_str());
 }
 
diff --git a/chrome/browser/conflicts/module_inspector_win_unittest.cc b/chrome/browser/conflicts/module_inspector_win_unittest.cc
index b44a2ad..021f4c9 100644
--- a/chrome/browser/conflicts/module_inspector_win_unittest.cc
+++ b/chrome/browser/conflicts/module_inspector_win_unittest.cc
@@ -69,7 +69,7 @@
 
 TEST_F(ModuleInspectorTest, OneModule) {
   AddModules({
-      {GetKernel32DllFilePath(), 0, 0, 1},
+      {GetKernel32DllFilePath(), 0, 0},
   });
 
   test_browser_thread_bundle_.RunUntilIdle();
@@ -79,11 +79,11 @@
 
 TEST_F(ModuleInspectorTest, MultipleModules) {
   AddModules({
-      {base::FilePath(), 0, 0, 1},
-      {base::FilePath(), 0, 0, 2},
-      {base::FilePath(), 0, 0, 3},
-      {base::FilePath(), 0, 0, 4},
-      {base::FilePath(), 0, 0, 5},
+      {base::FilePath(), 0, 0},
+      {base::FilePath(), 0, 0},
+      {base::FilePath(), 0, 0},
+      {base::FilePath(), 0, 0},
+      {base::FilePath(), 0, 0},
   });
 
   test_browser_thread_bundle_.RunUntilIdle();
diff --git a/chrome/browser/conflicts/module_list_filter_win_unittest.cc b/chrome/browser/conflicts/module_list_filter_win_unittest.cc
index f1ef918..797278a 100644
--- a/chrome/browser/conflicts/module_list_filter_win_unittest.cc
+++ b/chrome/browser/conflicts/module_list_filter_win_unittest.cc
@@ -122,10 +122,10 @@
 ModuleInfo CreateModuleInfo(const base::FilePath& module_path,
                             uint32_t module_size,
                             uint32_t module_time_date_stamp) {
-  ModuleInfo result(std::piecewise_construct,
-                    std::forward_as_tuple(module_path, module_size,
-                                          module_time_date_stamp, 0),
-                    std::forward_as_tuple());
+  ModuleInfo result(
+      std::piecewise_construct,
+      std::forward_as_tuple(module_path, module_size, module_time_date_stamp),
+      std::forward_as_tuple());
 
   result.second.inspection_result =
       base::make_optional<ModuleInspectionResult>();
diff --git a/chrome/browser/conflicts/third_party_conflicts_manager_win_unittest.cc b/chrome/browser/conflicts/third_party_conflicts_manager_win_unittest.cc
index 81845ee..a4a6f5f 100644
--- a/chrome/browser/conflicts/third_party_conflicts_manager_win_unittest.cc
+++ b/chrome/browser/conflicts/third_party_conflicts_manager_win_unittest.cc
@@ -96,7 +96,7 @@
 
   std::pair<ModuleInfoKey, ModuleInfoData> module_info(
       std::piecewise_construct,
-      std::forward_as_tuple(std::move(exe_path), 0, 0, 0),
+      std::forward_as_tuple(std::move(exe_path), 0, 0),
       std::forward_as_tuple());
 
   module_info.second.inspection_result =
diff --git a/chrome/browser/download/default_download_dir_policy_handler.cc b/chrome/browser/download/default_download_dir_policy_handler.cc
index 26e2a51..bfc63e2 100644
--- a/chrome/browser/download/default_download_dir_policy_handler.cc
+++ b/chrome/browser/download/default_download_dir_policy_handler.cc
@@ -40,9 +40,9 @@
 
   if (policies.Get(policy_name())->level == policy::POLICY_LEVEL_RECOMMENDED) {
     prefs->SetValue(prefs::kDownloadDefaultDirectory,
-                    std::make_unique<base::Value>(expanded_value));
+                    base::Value(expanded_value));
     prefs->SetValue(prefs::kSaveFileDefaultDirectory,
-                    std::make_unique<base::Value>(expanded_value));
+                    base::Value(expanded_value));
   }
 }
 
diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc
index f057e74..78c91f1 100644
--- a/chrome/browser/download/download_target_determiner.cc
+++ b/chrome/browser/download/download_target_determiner.cc
@@ -263,9 +263,10 @@
         content_disposition_header.filename().empty();
     if (should_replace_extension) {
       generated_filename = net::GenerateFileName(
-          download_->GetURL(), download_->GetContentDisposition(),
-          referrer_charset, suggested_filename, download_->GetMimeType(),
-          default_filename, true /* should_replace_extension */);
+          download_->GetURL(), std::string() /* content_disposition */,
+          referrer_charset, std::string() /* suggested_filename */,
+          download_->GetMimeType(), default_filename,
+          true /* should_replace_extension */);
     }
 
     confirmation_reason_ = NeedsConfirmation(generated_filename);
diff --git a/chrome/browser/download/notification/download_notification_interactive_uitest.cc b/chrome/browser/download/notification/download_notification_interactive_uitest.cc
index 6115b6c..60a5d1d 100644
--- a/chrome/browser/download/notification/download_notification_interactive_uitest.cc
+++ b/chrome/browser/download/notification/download_notification_interactive_uitest.cc
@@ -10,7 +10,9 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
@@ -37,11 +39,15 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_item_utils.h"
 #include "content/public/browser/download_manager.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/download_test_observer.h"
+#include "content/public/test/url_loader_interceptor.h"
+#include "net/http/http_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/url_request/url_request_slow_download_job.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "services/identity/public/cpp/identity_test_utils.h"
+#include "services/network/public/cpp/features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
@@ -92,6 +98,151 @@
   bool opened_;
 };
 
+// A Network Service based implementation of net::URLRequestSlowDownloadJob.
+class SlowDownloadInterceptor {
+ public:
+  static const char* kUnknownSizeUrl;
+  static const char* kKnownSizeUrl;
+  static const char* kFinishDownloadUrl;
+  static const char* kErrorDownloadUrl;
+
+  SlowDownloadInterceptor()
+      : interceptor_(base::BindRepeating(&SlowDownloadInterceptor::OnIntercept,
+                                         base::Unretained(this))),
+        handlers_(
+            {{kKnownSizeUrl, &SlowDownloadInterceptor::HandleKnownSize},
+             {kUnknownSizeUrl, &SlowDownloadInterceptor::HandleUnknownSize},
+             {kFinishDownloadUrl, &SlowDownloadInterceptor::HandleFinish},
+             {kErrorDownloadUrl, &SlowDownloadInterceptor::HandleError}}) {}
+
+ private:
+  using Handler = void (SlowDownloadInterceptor::*)(
+      content::URLLoaderInterceptor::RequestParams*);
+
+  // A wrapper around a URLLoaderInterceptor::RequestParams object that will
+  // make sure things are called on the right sequence. Owns itself.
+  class PendingRequest {
+   public:
+    PendingRequest(content::URLLoaderInterceptor::RequestParams&& params)
+        : params_(std::move(params)),
+          task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
+
+    void Complete(net::Error error_code) {
+      task_runner_->PostTask(
+          FROM_HERE, base::BindOnce(&PendingRequest::CompleteOnOriginalSequence,
+                                    base::Unretained(this), error_code));
+    }
+
+   private:
+    void CompleteOnOriginalSequence(net::Error error_code) {
+      network::URLLoaderCompletionStatus status;
+      status.error_code = error_code;
+      params_.client->OnComplete(status);
+      delete this;
+    }
+
+    content::URLLoaderInterceptor::RequestParams params_;
+    scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+    DISALLOW_COPY_AND_ASSIGN(PendingRequest);
+  };
+
+  // Can be called on the UI or IO thread depending on which factory we hooked.
+  bool OnIntercept(content::URLLoaderInterceptor::RequestParams* params) {
+    const auto& it = handlers_.find(params->url_request.url.spec());
+    if (it == handlers_.end())
+      return false;
+    Handler handler = it->second;
+    (this->*handler)(params);
+    return true;
+  }
+
+  void HandleKnownSize(content::URLLoaderInterceptor::RequestParams* params) {
+    SendHead(params, "application/octet-stream", /*content_length=*/1024);
+    SendBody(params, "some random data");
+    base::AutoLock lock(lock_);
+    pending_requests_.push_back(new PendingRequest(std::move(*params)));
+  }
+
+  void HandleUnknownSize(content::URLLoaderInterceptor::RequestParams* params) {
+    SendHead(params, "application/octet-stream", /*content_length=*/-1);
+    SendBody(params, "some random data");
+    base::AutoLock lock(lock_);
+    pending_requests_.push_back(new PendingRequest(std::move(*params)));
+  }
+
+  void HandleFinish(content::URLLoaderInterceptor::RequestParams* params) {
+    CompletePendingRequests(net::OK);
+    SendOk(params);
+  }
+
+  void HandleError(content::URLLoaderInterceptor::RequestParams* params) {
+    CompletePendingRequests(net::ERR_CONNECTION_RESET);
+    SendOk(params);
+  }
+
+  void CompletePendingRequests(net::Error error_code) {
+    base::AutoLock lock(lock_);
+    for (auto* request : pending_requests_)
+      request->Complete(error_code);
+    pending_requests_.clear();
+  }
+
+  static void SendOk(content::URLLoaderInterceptor::RequestParams* params) {
+    std::string response = "OK";
+    SendHead(params, "text/http", response.size());
+    SendBody(params, response);
+    network::URLLoaderCompletionStatus status;
+    status.error_code = net::OK;
+    params->client->OnComplete(status);
+  }
+
+  static void SendHead(content::URLLoaderInterceptor::RequestParams* params,
+                       std::string mime_type,
+                       int64_t content_length) {
+    network::ResourceResponseHead head;
+    std::string headers =
+        "HTTP/1.1 200 OK\n"
+        "Cache-Control: max-age=0\n";
+    headers += base::StringPrintf("Content-type: %s\n", mime_type.c_str());
+    if (content_length >= 0) {
+      headers += base::StringPrintf("Content-Length: %ld\n", content_length);
+      head.content_length = content_length;
+    }
+    head.headers = new net::HttpResponseHeaders(
+        net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length()));
+    head.headers->GetMimeType(&head.mime_type);
+    params->client->OnReceiveResponse(head);
+  }
+
+  static void SendBody(content::URLLoaderInterceptor::RequestParams* params,
+                       std::string data) {
+    mojo::DataPipe pipe(data.size());
+    ASSERT_TRUE(pipe.producer_handle.is_valid());
+    uint32_t write_size = data.size();
+    MojoResult result = pipe.producer_handle->WriteData(
+        data.c_str(), &write_size, MOJO_WRITE_DATA_FLAG_NONE);
+    ASSERT_EQ(MOJO_RESULT_OK, result);
+    ASSERT_EQ(data.size(), write_size);
+    ASSERT_TRUE(pipe.consumer_handle.is_valid());
+    params->client->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
+  }
+
+  content::URLLoaderInterceptor interceptor_;
+  const std::map<std::string, Handler> handlers_;
+  base::Lock lock_;
+  std::vector<PendingRequest*> pending_requests_ GUARDED_BY(lock_);
+};
+
+const char* SlowDownloadInterceptor::kUnknownSizeUrl =
+    net::URLRequestSlowDownloadJob::kUnknownSizeUrl;
+const char* SlowDownloadInterceptor::kKnownSizeUrl =
+    net::URLRequestSlowDownloadJob::kKnownSizeUrl;
+const char* SlowDownloadInterceptor::kFinishDownloadUrl =
+    net::URLRequestSlowDownloadJob::kFinishDownloadUrl;
+const char* SlowDownloadInterceptor::kErrorDownloadUrl =
+    net::URLRequestSlowDownloadJob::kErrorDownloadUrl;
+
 // Utility method to retrieve a notification object by id. Warning: this will
 // check the last display service that was created. If there's a normal and an
 // incognito one, you may want to be explicit.
@@ -124,11 +275,18 @@
     display_service_ = std::make_unique<NotificationDisplayServiceTester>(
         browser()->profile());
 
-    base::PostTaskWithTraits(
-        FROM_HERE, {content::BrowserThread::IO},
-        base::BindOnce(&net::URLRequestSlowDownloadJob::AddUrlHandler));
+    if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
+        !content::IsNetworkServiceRunningInProcess()) {
+      interceptor_ = std::make_unique<SlowDownloadInterceptor>();
+    } else {
+      base::PostTaskWithTraits(
+          FROM_HERE, {content::BrowserThread::IO},
+          base::BindOnce(&net::URLRequestSlowDownloadJob::AddUrlHandler));
+    }
   }
 
+  void TearDownOnMainThread() override { interceptor_.reset(); }
+
  protected:
   content::DownloadManager* GetDownloadManager(Browser* browser) {
     return content::BrowserContext::GetDownloadManager(browser->profile());
@@ -140,12 +298,13 @@
         GetDownloadManager(browser()), wait_count,
         content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
     ui_test_utils::NavigateToURL(
-        browser(), GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+        browser(), GURL(SlowDownloadInterceptor::kFinishDownloadUrl));
     download_terminal_observer.WaitForFinished();
   }
 
   std::unique_ptr<NotificationDisplayServiceTester> display_service_;
   std::unique_ptr<NotificationDisplayServiceTester> incognito_display_service_;
+  std::unique_ptr<SlowDownloadInterceptor> interceptor_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DownloadNotificationTestBase);
@@ -205,7 +364,7 @@
 
   void CreateDownload() {
     return CreateDownloadForBrowserAndURL(
-        browser(), GURL(net::URLRequestSlowDownloadJob::kKnownSizeUrl));
+        browser(), GURL(SlowDownloadInterceptor::kKnownSizeUrl));
   }
 
   // Returns the correct display service for the given Browser. If |browser| is
@@ -273,7 +432,7 @@
         GetDownloadManager(browser()), 1u, /* wait_count */
         content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
     ui_test_utils::NavigateToURL(
-        browser(), GURL(net::URLRequestSlowDownloadJob::kErrorDownloadUrl));
+        browser(), GURL(SlowDownloadInterceptor::kErrorDownloadUrl));
     download_interrupted_observer.WaitForFinished();
   }
 
@@ -527,8 +686,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, DownloadMultipleFiles) {
-  GURL url1(net::URLRequestSlowDownloadJob::kUnknownSizeUrl);
-  GURL url2(net::URLRequestSlowDownloadJob::kKnownSizeUrl);
+  GURL url1(SlowDownloadInterceptor::kUnknownSizeUrl);
+  GURL url2(SlowDownloadInterceptor::kKnownSizeUrl);
 
   // Starts the 1st download.
   ui_test_utils::NavigateToURL(browser(), url1);
@@ -630,7 +789,7 @@
   EXPECT_TRUE(notification());
 
   // Starts the second download.
-  GURL url(net::URLRequestSlowDownloadJob::kKnownSizeUrl);
+  GURL url(SlowDownloadInterceptor::kKnownSizeUrl);
   ui_test_utils::NavigateToURL(browser(), url);
   WaitForDownloadNotification();
 
@@ -696,8 +855,8 @@
   PrepareIncognitoBrowser();
 
   // Starts an incognito download.
-  CreateDownloadForBrowserAndURL(
-      incognito_browser(), GURL(net::URLRequestSlowDownloadJob::kKnownSizeUrl));
+  CreateDownloadForBrowserAndURL(incognito_browser(),
+                                 GURL(SlowDownloadInterceptor::kKnownSizeUrl));
 
   EXPECT_EQ(l10n_util::GetStringFUTF16(
                 IDS_DOWNLOAD_STATUS_IN_PROGRESS_TITLE,
@@ -712,8 +871,7 @@
       GetDownloadManager(incognito_browser()), 1,
       content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
   ui_test_utils::NavigateToURL(
-      incognito_browser(),
-      GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+      incognito_browser(), GURL(SlowDownloadInterceptor::kFinishDownloadUrl));
   download_terminal_observer.WaitForFinished();
 
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_COMPLETE_TITLE),
@@ -740,8 +898,8 @@
                        SimultaneousIncognitoAndNormalDownloads) {
   PrepareIncognitoBrowser();
 
-  GURL url_incognito(net::URLRequestSlowDownloadJob::kUnknownSizeUrl);
-  GURL url_normal(net::URLRequestSlowDownloadJob::kKnownSizeUrl);
+  GURL url_incognito(SlowDownloadInterceptor::kUnknownSizeUrl);
+  GURL url_normal(SlowDownloadInterceptor::kKnownSizeUrl);
 
   // Starts the incognito download.
   ui_test_utils::NavigateToURL(incognito_browser(), url_incognito);
@@ -902,7 +1060,7 @@
                        DownloadMultipleFiles) {
   AddAllUsers();
 
-  GURL url(net::URLRequestSlowDownloadJob::kUnknownSizeUrl);
+  GURL url(SlowDownloadInterceptor::kUnknownSizeUrl);
 
   Profile* profile1 = GetProfileByIndex(1);
   Profile* profile2 = GetProfileByIndex(2);
@@ -993,9 +1151,9 @@
       GetDownloadManager(browser2), 2u /* wait_count */,
       content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
   ui_test_utils::NavigateToURL(
-      browser1, GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+      browser1, GURL(SlowDownloadInterceptor::kFinishDownloadUrl));
   ui_test_utils::NavigateToURL(
-      browser2, GURL(net::URLRequestSlowDownloadJob::kFinishDownloadUrl));
+      browser2, GURL(SlowDownloadInterceptor::kFinishDownloadUrl));
   download_terminal_observer.WaitForFinished();
   download_terminal_observer2.WaitForFinished();
 
diff --git a/chrome/browser/extensions/policy_handlers.cc b/chrome/browser/extensions/policy_handlers.cc
index 4be1677..0e2eda1 100644
--- a/chrome/browser/extensions/policy_handlers.cc
+++ b/chrome/browser/extensions/policy_handlers.cc
@@ -52,7 +52,9 @@
 void ExtensionListPolicyHandler::ApplyList(
     std::unique_ptr<base::ListValue> filtered_list,
     PrefValueMap* prefs) {
-  prefs->SetValue(pref_path_, std::move(filtered_list));
+  DCHECK(filtered_list);
+  prefs->SetValue(pref_path_,
+                  base::Value::FromUniquePtrValue(std::move(filtered_list)));
 }
 
 // ExtensionInstallListPolicyHandler implementation ----------------------------
@@ -75,9 +77,9 @@
     const policy::PolicyMap& policies,
     PrefValueMap* prefs) {
   const base::Value* value = nullptr;
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+  base::DictionaryValue dict;
   if (CheckAndGetValue(policies, nullptr, &value) && value &&
-      ParseList(value, dict.get(), nullptr)) {
+      ParseList(value, &dict, nullptr)) {
     prefs->SetValue(pref_name_, std::move(dict));
   }
 }
@@ -212,7 +214,7 @@
     return;
   const base::Value* value = policies.GetValue(policy_name());
   if (value)
-    prefs->SetValue(pref_path_, value->CreateDeepCopy());
+    prefs->SetValue(pref_path_, value->Clone());
 }
 
 // ExtensionSettingsPolicyHandler implementation  ------------------------------
@@ -346,7 +348,8 @@
   std::unique_ptr<base::Value> policy_value;
   if (!CheckAndGetValue(policies, NULL, &policy_value) || !policy_value)
     return;
-  prefs->SetValue(pref_names::kExtensionManagement, std::move(policy_value));
+  prefs->SetValue(pref_names::kExtensionManagement,
+                  base::Value::FromUniquePtrValue(std::move(policy_value)));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.cc b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
deleted file mode 100644
index 1792109..0000000
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.cc
+++ /dev/null
@@ -1,479 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media/android/remote/remote_media_player_bridge.h"
-
-#include <utility>
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "chrome/browser/media/android/remote/remote_media_player_manager.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/web_contents.h"
-#include "jni/RemoteMediaPlayerBridge_jni.h"
-#include "media/base/android/media_common_android.h"
-#include "media/base/android/media_resource_getter.h"
-#include "media/base/timestamp_constants.h"
-#include "net/base/escape.h"
-#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/android/java_bitmap.h"
-
-using base::android::ConvertUTF8ToJavaString;
-using base::android::ConvertJavaStringToUTF8;
-using base::android::JavaParamRef;
-using base::android::ScopedJavaLocalRef;
-using base::android::AttachCurrentThread;
-using content::BrowserThread;
-using media::MediaPlayerAndroid;
-
-namespace remote_media {
-
-RemoteMediaPlayerBridge::RemoteMediaPlayerBridge(
-    int player_id,
-    const std::string& user_agent,
-    RemoteMediaPlayerManager* manager)
-    : MediaPlayerAndroid(player_id,
-                         manager,
-                         base::DoNothing(),
-                         manager->GetLocalPlayer(player_id)->frame_url()),
-      width_(0),
-      height_(0),
-      url_(manager->GetLocalPlayer(player_id)->GetUrl()),
-      site_for_cookies_(
-          manager->GetLocalPlayer(player_id)->GetSiteForCookies()),
-      user_agent_(user_agent),
-      weak_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = base::android::AttachCurrentThread();
-  DCHECK(env);
-  ScopedJavaLocalRef<jstring> j_url_string;
-  if (url_.is_valid()) {
-    // Escape the URL to make it safe to use. Don't escape existing escape
-    // sequences though.
-    std::string escaped_url = net::EscapeExternalHandlerValue(url_.spec());
-    // Create a Java String for the URL.
-    j_url_string = ConvertUTF8ToJavaString(env, escaped_url);
-  }
-  ScopedJavaLocalRef<jstring> j_frame_url_string;
-  GURL frameUrl = GetLocalPlayer()->frame_url();
-  if (frameUrl.is_valid()) {
-    // Create a Java String for the URL.
-    j_frame_url_string = ConvertUTF8ToJavaString(env, frameUrl.spec());
-  }
-  java_bridge_.Reset(Java_RemoteMediaPlayerBridge_create(
-      env, reinterpret_cast<intptr_t>(this), j_url_string, j_frame_url_string,
-      ConvertUTF8ToJavaString(env, user_agent)));
-}
-
-RemoteMediaPlayerBridge::~RemoteMediaPlayerBridge() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  DCHECK(env);
-  Java_RemoteMediaPlayerBridge_destroy(env, java_bridge_);
-  Release();
-}
-
-bool RemoteMediaPlayerBridge::HasVideo() const {
-  NOTIMPLEMENTED();
-  return true;
-}
-
-bool RemoteMediaPlayerBridge::HasAudio() const {
-  NOTIMPLEMENTED();
-  return true;
-}
-
-int RemoteMediaPlayerBridge::GetVideoWidth() {
-  MediaPlayerAndroid* local_player = GetLocalPlayer();
-  if (!local_player)
-    return 0;
-  return local_player->GetVideoWidth();
-}
-
-int RemoteMediaPlayerBridge::GetVideoHeight() {
-  MediaPlayerAndroid* local_player = GetLocalPlayer();
-  if (!local_player)
-    return 0;
-  return local_player->GetVideoHeight();
-}
-
-void RemoteMediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
-  width_ = width;
-  height_ = height;
-  MediaPlayerAndroid::OnVideoSizeChanged(width, height);
-}
-
-void RemoteMediaPlayerBridge::OnPlaybackComplete() {
-  time_update_timer_.Stop();
-  MediaPlayerAndroid::OnPlaybackComplete();
-}
-
-void RemoteMediaPlayerBridge::OnMediaInterrupted() {}
-
-void RemoteMediaPlayerBridge::StartInternal() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  Java_RemoteMediaPlayerBridge_start(env, java_bridge_);
-  if (!time_update_timer_.IsRunning()) {
-    time_update_timer_.Start(
-        FROM_HERE,
-        base::TimeDelta::FromMilliseconds(media::kTimeUpdateInterval),
-        this, &RemoteMediaPlayerBridge::OnTimeUpdateTimerFired);
-  }
-}
-
-void RemoteMediaPlayerBridge::PauseInternal() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  Java_RemoteMediaPlayerBridge_pause(env, java_bridge_);
-  time_update_timer_.Stop();
-}
-
-void RemoteMediaPlayerBridge::OnTimeUpdateTimerFired() {
-  manager()->OnTimeUpdate(
-      player_id(), GetCurrentTime(), base::TimeTicks::Now());
-}
-
-void RemoteMediaPlayerBridge::PauseLocal(JNIEnv* env,
-                                         const JavaParamRef<jobject>& obj) {
-  MediaPlayerAndroid* local_player = GetLocalPlayer();
-  if (!local_player)
-    return;
-  local_player->Pause(true);
-  static_cast<RemoteMediaPlayerManager*>(manager())->OnPaused(player_id());
-}
-
-jint RemoteMediaPlayerBridge::GetLocalPosition(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  MediaPlayerAndroid* local_player = GetLocalPlayer();
-  if (!local_player)
-    return 0;
-  base::TimeDelta time = local_player->GetCurrentTime();
-  return static_cast<jint>(time.InMilliseconds());
-}
-
-void RemoteMediaPlayerBridge::OnCastStarting(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& casting_message) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  static_cast<RemoteMediaPlayerManager*>(manager())->SwitchToRemotePlayer(
-      player_id(), ConvertJavaStringToUTF8(env, casting_message));
-  if (!time_update_timer_.IsRunning()) {
-    time_update_timer_.Start(
-        FROM_HERE,
-        base::TimeDelta::FromMilliseconds(media::kTimeUpdateInterval), this,
-        &RemoteMediaPlayerBridge::OnTimeUpdateTimerFired);
-  }
-}
-
-void RemoteMediaPlayerBridge::OnCastStarted(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  static_cast<RemoteMediaPlayerManager*>(manager())->OnRemotePlaybackStarted(
-      player_id());
-}
-
-void RemoteMediaPlayerBridge::OnCastStopping(JNIEnv* env,
-                                             const JavaParamRef<jobject>& obj) {
-  static_cast<RemoteMediaPlayerManager*>(manager())
-      ->SwitchToLocalPlayer(player_id());
-}
-
-void RemoteMediaPlayerBridge::OnSeekCompleted(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  OnSeekComplete();
-}
-
-void RemoteMediaPlayerBridge::Pause(bool is_media_related_action) {
-  // Ignore the pause if it's not from an event that is explicitly telling
-  // the video to pause. It's possible for Pause() to be called for other
-  // reasons, such as freeing resources, etc. and during those times, the
-  // remote video playback should not be paused.
-  if (is_media_related_action) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    JNIEnv* env = AttachCurrentThread();
-    Java_RemoteMediaPlayerBridge_pause(env, java_bridge_);
-    time_update_timer_.Stop();
-  }
-}
-
-void RemoteMediaPlayerBridge::SetVideoSurface(gl::ScopedJavaSurface surface) {
-  // The surface is reset whenever the fullscreen view is destroyed or created.
-  // Since the remote player doesn't use it, we forward it to the local player
-  // for the time when user disconnects and resumes local playback
-  // (see crbug.com/420690).
-  MediaPlayerAndroid* local_player = GetLocalPlayer();
-  if (!local_player)
-    return;
-  local_player->SetVideoSurface(std::move(surface));
-}
-
-void RemoteMediaPlayerBridge::OnPlaying(JNIEnv* env,
-                                        const JavaParamRef<jobject>& obj) {
-  static_cast<RemoteMediaPlayerManager *>(manager())->OnPlaying(player_id());
-}
-
-void RemoteMediaPlayerBridge::OnPaused(JNIEnv* env,
-                                       const JavaParamRef<jobject>& obj) {
-  static_cast<RemoteMediaPlayerManager *>(manager())->OnPaused(player_id());
-}
-
-void RemoteMediaPlayerBridge::OnRouteUnselected(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  casting_message_.reset();
-  static_cast<RemoteMediaPlayerManager *>(manager())->OnRemoteDeviceUnselected(
-      player_id());
-}
-
-void RemoteMediaPlayerBridge::OnPlaybackFinished(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  static_cast<RemoteMediaPlayerManager *>(manager())->OnRemotePlaybackFinished(
-      player_id());
-}
-
-void RemoteMediaPlayerBridge::OnRouteAvailabilityChanged(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    int availability) {
-  static_cast<RemoteMediaPlayerManager *>(manager())->
-      OnRouteAvailabilityChanged(
-          player_id(),
-          static_cast<blink::WebRemotePlaybackAvailability>(availability));
-}
-
-void RemoteMediaPlayerBridge::RequestRemotePlayback() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  MediaPlayerAndroid* local_player = GetLocalPlayer();
-  if (!local_player)
-    return;
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-
-  Java_RemoteMediaPlayerBridge_requestRemotePlayback(
-      env, java_bridge_, local_player->GetCurrentTime().InMilliseconds());
-}
-
-void RemoteMediaPlayerBridge::RequestRemotePlaybackControl() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-
-  Java_RemoteMediaPlayerBridge_requestRemotePlaybackControl(env, java_bridge_);
-}
-
-void RemoteMediaPlayerBridge::RequestRemotePlaybackStop() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-
-  Java_RemoteMediaPlayerBridge_requestRemotePlaybackStop(env, java_bridge_);
-}
-
-void RemoteMediaPlayerBridge::SetNativePlayer() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-
-  Java_RemoteMediaPlayerBridge_setNativePlayer(env, java_bridge_);
-}
-
-void RemoteMediaPlayerBridge::OnPlayerCreated() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-
-  Java_RemoteMediaPlayerBridge_onPlayerCreated(env, java_bridge_);
-}
-
-void RemoteMediaPlayerBridge::OnPlayerDestroyed() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-
-  Java_RemoteMediaPlayerBridge_onPlayerDestroyed(env, java_bridge_);
-}
-
-std::string RemoteMediaPlayerBridge::GetCastingMessage() {
-  return casting_message_ ?
-      *casting_message_ : std::string();
-}
-
-void RemoteMediaPlayerBridge::SetPosterBitmap(
-    const std::vector<SkBitmap>& bitmaps) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-
-  if (bitmaps.empty()) {
-    Java_RemoteMediaPlayerBridge_setPosterBitmap(env, java_bridge_, nullptr);
-  } else {
-    ScopedJavaLocalRef<jobject> j_poster_bitmap;
-    j_poster_bitmap = gfx::ConvertToJavaBitmap(&(bitmaps[0]));
-
-    Java_RemoteMediaPlayerBridge_setPosterBitmap(env, java_bridge_,
-                                                 j_poster_bitmap);
-  }
-}
-
-void RemoteMediaPlayerBridge::Start() {
-  StartInternal();
-}
-
-void RemoteMediaPlayerBridge::SeekTo(base::TimeDelta time) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // TODO(aberent) Move the checks to the Java side.
-  base::TimeDelta duration = GetDuration();
-
-  if (time > duration)
-    time = duration;
-
-  // Seeking to an invalid position may cause media player to stuck in an
-  // error state.
-  if (time < base::TimeDelta()) {
-    DCHECK_EQ(-1.0, time.InMillisecondsF());
-    return;
-  }
-
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-  int time_msec = static_cast<int>(time.InMilliseconds());
-  Java_RemoteMediaPlayerBridge_seekTo(env, java_bridge_, time_msec);
-}
-
-void RemoteMediaPlayerBridge::Release() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  time_update_timer_.Stop();
-  JNIEnv* env = AttachCurrentThread();
-  Java_RemoteMediaPlayerBridge_release(env, java_bridge_);
-  DetachListener();
-}
-
-void RemoteMediaPlayerBridge::UpdateEffectiveVolumeInternal(
-    double effective_volume) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-  Java_RemoteMediaPlayerBridge_setVolume(env, java_bridge_,
-                                         GetEffectiveVolume());
-}
-
-base::TimeDelta RemoteMediaPlayerBridge::GetCurrentTime() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  return base::TimeDelta::FromMilliseconds(
-      Java_RemoteMediaPlayerBridge_getCurrentPosition(env, java_bridge_));
-}
-
-base::TimeDelta RemoteMediaPlayerBridge::GetDuration() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  const int duration_ms =
-      Java_RemoteMediaPlayerBridge_getDuration(env, java_bridge_);
-  // Sometimes we can't get the duration remotely, but the local media player
-  // knows it.
-  // TODO (aberent) This is for YouTube. Remove it when the YouTube receiver is
-  // fixed.
-  if (duration_ms == 0) {
-    MediaPlayerAndroid* local_player = GetLocalPlayer();
-    if (!local_player)
-      return media::kInfiniteDuration;
-    return local_player->GetDuration();
-  }
-  return duration_ms < 0 ? media::kInfiniteDuration
-                         : base::TimeDelta::FromMilliseconds(duration_ms);
-}
-
-bool RemoteMediaPlayerBridge::IsPlaying() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-  jboolean result = Java_RemoteMediaPlayerBridge_isPlaying(env, java_bridge_);
-  return result;
-}
-
-bool RemoteMediaPlayerBridge::CanPause() {
-  return true;
-}
-
-bool RemoteMediaPlayerBridge::CanSeekForward() {
-  return true;
-}
-
-bool RemoteMediaPlayerBridge::CanSeekBackward() {
-  return true;
-}
-
-bool RemoteMediaPlayerBridge::IsPlayerReady() {
-  return true;
-}
-
-GURL RemoteMediaPlayerBridge::GetUrl() {
-  return url_;
-}
-
-GURL RemoteMediaPlayerBridge::GetSiteForCookies() {
-  return site_for_cookies_;
-}
-
-void RemoteMediaPlayerBridge::Initialize() {
-  cookies_.clear();
-  media::MediaResourceGetter* resource_getter =
-      manager()->GetMediaResourceGetter();
-  resource_getter->GetCookies(
-      url_, site_for_cookies_,
-      base::Bind(&RemoteMediaPlayerBridge::OnCookiesRetrieved,
-                 weak_factory_.GetWeakPtr()));
-}
-
-base::android::ScopedJavaLocalRef<jstring> RemoteMediaPlayerBridge::GetTitle(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  base::string16 title;
-  auto* contents =
-      static_cast<RemoteMediaPlayerManager*>(manager())->web_contents();
-  if (contents)
-    title = contents->GetTitle();
-  return base::android::ConvertUTF16ToJavaString(env, title);
-}
-
-void RemoteMediaPlayerBridge::OnError(
-    JNIEnv* env, const base::android::JavaParamRef<jobject>& obj) {
-      // TODO(https://crbug.com/585379) implement some useful codes for remote
-      // playback. None of the existing MediaPlayerAndroid codes are
-      // relevant for remote playback.
-      manager()->OnError(player_id(), MEDIA_ERROR_INVALID_CODE);
-}
-
-void RemoteMediaPlayerBridge::OnCancelledRemotePlaybackRequest(
-    JNIEnv* env, const base::android::JavaParamRef<jobject>& obj) {
-  static_cast<RemoteMediaPlayerManager*>(manager())
-      ->OnCancelledRemotePlaybackRequest(player_id());
-}
-
-
-void RemoteMediaPlayerBridge::OnCookiesRetrieved(const std::string& cookies) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // TODO(aberent) Do we need to retrieve auth credentials for basic
-  // authentication? MediaPlayerBridge does.
-  cookies_ = cookies;
-  JNIEnv* env = AttachCurrentThread();
-  DCHECK(env);
-  Java_RemoteMediaPlayerBridge_setCookies(
-      env, java_bridge_, ConvertUTF8ToJavaString(env, cookies));
-}
-
-MediaPlayerAndroid* RemoteMediaPlayerBridge::GetLocalPlayer() {
-  return static_cast<RemoteMediaPlayerManager*>(manager())->GetLocalPlayer(
-      player_id());
-}
-
-}  // namespace remote_media
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.h b/chrome/browser/media/android/remote/remote_media_player_bridge.h
deleted file mode 100644
index 96d5ecb..0000000
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.h
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_ANDROID_REMOTE_REMOTE_MEDIA_PLAYER_BRIDGE_H_
-#define CHROME_BROWSER_MEDIA_ANDROID_REMOTE_REMOTE_MEDIA_PLAYER_BRIDGE_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "media/base/android/media_player_bridge.h"
-
-class SkBitmap;
-
-// This is the version of MediaPlayerBridge that handles the remote media
-// playback.
-
-namespace remote_media {
-
-class RemoteMediaPlayerManager;
-
-class RemoteMediaPlayerBridge : public media::MediaPlayerAndroid {
- public:
-  RemoteMediaPlayerBridge(int player_id,
-                          const std::string& user_agent,
-                          RemoteMediaPlayerManager* manager);
-  ~RemoteMediaPlayerBridge() override;
-
-  // Initialize this object.
-  virtual void Initialize();
-
-  // MediaPlayerAndroid implementation.
-  void SetVideoSurface(gl::ScopedJavaSurface surface) override;
-  void Start() override;
-  void Pause(bool is_media_related_action) override;
-  void SeekTo(base::TimeDelta timestamp) override;
-  void Release() override;
-  bool HasVideo() const override;
-  bool HasAudio() const override;
-  int GetVideoWidth() override;
-  int GetVideoHeight() override;
-  base::TimeDelta GetCurrentTime() override;
-  base::TimeDelta GetDuration() override;
-  bool IsPlaying() override;
-  bool CanPause() override;
-  bool CanSeekForward() override;
-  bool CanSeekBackward() override;
-  bool IsPlayerReady() override;
-  GURL GetUrl() override;
-  GURL GetSiteForCookies() override;
-
-  // JNI functions
-  void OnPlaying(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
-  void OnPaused(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
-  void OnRouteUnselected(JNIEnv* env,
-                         const base::android::JavaParamRef<jobject>& obj);
-  void OnPlaybackFinished(JNIEnv* env,
-                          const base::android::JavaParamRef<jobject>& obj);
-  void OnRouteAvailabilityChanged(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      int availability);
-  base::android::ScopedJavaLocalRef<jstring> GetTitle(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
-  void PauseLocal(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
-  jint GetLocalPosition(JNIEnv* env,
-                        const base::android::JavaParamRef<jobject>& obj);
-  void OnCastStarting(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jstring>& casting_message);
-  void OnCastStarted(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
-  void OnCastStopping(JNIEnv* env,
-                      const base::android::JavaParamRef<jobject>& obj);
-  void OnSeekCompleted(JNIEnv* env,
-                       const base::android::JavaParamRef<jobject>& obj);
-  void OnError(JNIEnv *env,
-               const base::android::JavaParamRef<jobject>& obj);
-  void OnCancelledRemotePlaybackRequest(
-      JNIEnv *env,
-      const base::android::JavaParamRef<jobject>& obj);
-
-  // Wrappers for calls to Java used by the remote media player manager
-  void RequestRemotePlayback();
-  void RequestRemotePlaybackControl();
-  void RequestRemotePlaybackStop();
-  void SetNativePlayer();
-  void OnPlayerCreated();
-  void OnPlayerDestroyed();
-
-  // Gets the message to display on the embedded player while casting.
-  std::string GetCastingMessage();
-
-  // Tell the java side about the poster image for a given media.
-  void SetPosterBitmap(const std::vector<SkBitmap>& bitmaps);
-
- protected:
-  // MediaPlayerAndroid implementation.
-  void OnVideoSizeChanged(int width, int height) override;
-  void OnPlaybackComplete() override;
-  void OnMediaInterrupted() override;
-
- private:
-  // MediaPlayerAndroid implementation
-  void UpdateEffectiveVolumeInternal(double effective_volume) override;
-
-  // Functions that implements media player control.
-  void StartInternal();
-  void PauseInternal();
-
-  // Called when |time_update_timer_| fires.
-  void OnTimeUpdateTimerFired();
-
-  // Callback function passed to |resource_getter_|. Called when the cookies
-  // are retrieved.
-  void OnCookiesRetrieved(const std::string& cookies);
-
-  media::MediaPlayerAndroid* GetLocalPlayer();
-
-  int width_;
-  int height_;
-  base::RepeatingTimer time_update_timer_;
-  base::TimeDelta duration_;
-
-  // Url for playback.
-  GURL url_;
-
-  // First party url for cookies.
-  GURL site_for_cookies_;
-
-  // Cookies for |url_|.
-  std::string cookies_;
-
-  // User agent string to be used for media player.
-  const std::string user_agent_;
-
-  base::android::ScopedJavaGlobalRef<jobject> java_bridge_;
-  std::unique_ptr<std::string> casting_message_;
-
-  // NOTE: Weak pointers must be invalidated before all other member variables.
-  base::WeakPtrFactory<RemoteMediaPlayerBridge> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(RemoteMediaPlayerBridge);
-};
-
-} // namespace remote_media
-
-#endif  // CHROME_BROWSER_MEDIA_ANDROID_REMOTE_REMOTE_MEDIA_PLAYER_BRIDGE_H_
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.cc b/chrome/browser/media/android/remote/remote_media_player_manager.cc
deleted file mode 100644
index 6c810b7..0000000
--- a/chrome/browser/media/android/remote/remote_media_player_manager.cc
+++ /dev/null
@@ -1,297 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media/android/remote/remote_media_player_manager.h"
-
-#include "base/bind.h"
-#include "chrome/browser/android/tab_android.h"
-#include "chrome/browser/chrome_content_browser_client.h"
-#include "content/common/media/media_player_messages_android.h"
-#include "content/public/browser/web_contents.h"
-#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/android/java_bitmap.h"
-
-using media::MediaPlayerAndroid;
-
-static const int MAX_POSTER_BITMAP_SIZE = 1024 * 1024;
-
-namespace remote_media {
-
-RemoteMediaPlayerManager::RemoteMediaPlayerManager(
-    content::RenderFrameHost* render_frame_host)
-    : BrowserMediaPlayerManager(render_frame_host),
-      weak_ptr_factory_(this) {
-}
-
-RemoteMediaPlayerManager::~RemoteMediaPlayerManager() {
-  for (auto& player : alternative_players_)
-    player.release()->DeleteOnCorrectThread();
-
-  alternative_players_.clear();
-}
-
-void RemoteMediaPlayerManager::OnStart(int player_id) {
-  RemoteMediaPlayerBridge* remote_player = GetRemotePlayer(player_id);
-  if (remote_player && IsPlayingRemotely(player_id))
-    remote_player->Start();
-
-  BrowserMediaPlayerManager::OnStart(player_id);
-}
-
-void RemoteMediaPlayerManager::OnInitialize(
-    const MediaPlayerHostMsg_Initialize_Params& media_params) {
-  BrowserMediaPlayerManager::OnInitialize(media_params);
-
-  if (GetPlayer(media_params.player_id)) {
-    RemoteMediaPlayerBridge* remote_player =
-        CreateRemoteMediaPlayer(media_params.player_id);
-    remote_player->OnPlayerCreated();
-  }
-}
-
-void RemoteMediaPlayerManager::OnDestroyPlayer(int player_id) {
-  RemoteMediaPlayerBridge* player = GetRemotePlayer(player_id);
-  if (player)
-    player->OnPlayerDestroyed();
-  poster_urls_.erase(player_id);
-  BrowserMediaPlayerManager::OnDestroyPlayer(player_id);
-}
-
-void RemoteMediaPlayerManager::OnSuspendAndReleaseResources(int player_id) {
-  // We only want to release resources of local players.
-  if (!IsPlayingRemotely(player_id))
-    BrowserMediaPlayerManager::OnSuspendAndReleaseResources(player_id);
-}
-
-void RemoteMediaPlayerManager::OnRequestRemotePlayback(int player_id) {
-  RemoteMediaPlayerBridge* player = GetRemotePlayer(player_id);
-  if (player)
-    player->RequestRemotePlayback();
-}
-
-void RemoteMediaPlayerManager::OnRequestRemotePlaybackControl(int player_id) {
-  RemoteMediaPlayerBridge* player = GetRemotePlayer(player_id);
-  if (player)
-    player->RequestRemotePlaybackControl();
-}
-
-void RemoteMediaPlayerManager::OnRequestRemotePlaybackStop(int player_id) {
-  RemoteMediaPlayerBridge* player = GetRemotePlayer(player_id);
-  if (player)
-    player->RequestRemotePlaybackStop();
-}
-
-bool RemoteMediaPlayerManager::IsPlayingRemotely(int player_id) {
-  return players_playing_remotely_.count(player_id) != 0;
-}
-
-int RemoteMediaPlayerManager::GetTabId() {
-  if (!web_contents())
-    return -1;
-
-  TabAndroid* tab = TabAndroid::FromWebContents(web_contents());
-  if (!tab)
-    return -1;
-
-  return tab->GetAndroidId();
-}
-
-void RemoteMediaPlayerManager::FetchPosterBitmap(int player_id) {
-  RemoteMediaPlayerBridge* player = GetRemotePlayer(player_id);
-  if (poster_urls_.count(player_id) == 0 ||
-      poster_urls_[player_id].is_empty()) {
-    if (player)
-      player->SetPosterBitmap(std::vector<SkBitmap>());
-    return;
-  }
-  content::WebContents::ImageDownloadCallback callback =
-      base::BindOnce(&RemoteMediaPlayerManager::DidDownloadPoster,
-                     weak_ptr_factory_.GetWeakPtr(), player_id);
-  web_contents()->DownloadImage(
-      poster_urls_[player_id],
-      false,  // is_favicon, false so that cookies will be used.
-      MAX_POSTER_BITMAP_SIZE,  // max_bitmap_size, 0 means no limit.
-      false,                   // normal cache policy.
-      std::move(callback));
-}
-
-void RemoteMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
-  // OnSetPoster is called when the attibutes of the video element are parsed,
-  // which may be before OnInitialize is called, so we can't assume that the
-  // players wil exist.
-  poster_urls_[player_id] = url;
-}
-
-void RemoteMediaPlayerManager::ReleaseResources(int player_id) {
-  if (IsPlayingRemotely(player_id))
-    return;
-  BrowserMediaPlayerManager::ReleaseResources(player_id);
-}
-
-void RemoteMediaPlayerManager::DidDownloadPoster(
-    int player_id,
-    int id,
-    int http_status_code,
-    const GURL& image_url,
-    const std::vector<SkBitmap>& bitmaps,
-    const std::vector<gfx::Size>& original_bitmap_sizes) {
-  RemoteMediaPlayerBridge* player = GetRemotePlayer(player_id);
-  if (player)
-    player->SetPosterBitmap(bitmaps);
-}
-
-RemoteMediaPlayerBridge* RemoteMediaPlayerManager::CreateRemoteMediaPlayer(
-    int player_id) {
-  alternative_players_.push_back(std::make_unique<RemoteMediaPlayerBridge>(
-      player_id, GetUserAgent(), this));
-  RemoteMediaPlayerBridge* remote =
-      static_cast<RemoteMediaPlayerBridge*>(alternative_players_.back().get());
-  remote->Initialize();
-  return remote;
-}
-
-bool RemoteMediaPlayerManager::SwapCurrentPlayer(int player_id) {
-  // Find the alternative player to swap the current one with.
-  auto it = GetAlternativePlayer(player_id);
-  if (it == alternative_players_.end())
-    return false;
-
-  // Release ownership of the alternative player.
-  std::unique_ptr<MediaPlayerAndroid> old_player =
-      SwapPlayer(player_id, std::move(*it));
-  alternative_players_.erase(it);
-  if (!old_player) {
-    return false;
-  }
-
-  alternative_players_.push_back(std::move(old_player));
-  return true;
-}
-
-void RemoteMediaPlayerManager::SwitchToRemotePlayer(
-    int player_id,
-    const std::string& casting_message) {
-  DCHECK(!IsPlayingRemotely(player_id));
-  if (!SwapCurrentPlayer(player_id))
-    return;
-  players_playing_remotely_.insert(player_id);
-  Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(), player_id));
-  Send(new MediaPlayerMsg_ConnectedToRemoteDevice(RoutingID(), player_id,
-                                                  casting_message));
-  // The remote player will want the poster bitmap, however, to avoid wasting
-  // memory we don't fetch it until we are likely to need it.
-  FetchPosterBitmap(player_id);
-}
-
-void RemoteMediaPlayerManager::SwitchToLocalPlayer(int player_id) {
-  DCHECK(IsPlayingRemotely(player_id));
-  SwapCurrentPlayer(player_id);
-  players_playing_remotely_.erase(player_id);
-  Send(new MediaPlayerMsg_DisconnectedFromRemoteDevice(RoutingID(), player_id));
-}
-
-void RemoteMediaPlayerManager::ReplaceRemotePlayerWithLocal(int player_id) {
-  if (!IsPlayingRemotely(player_id))
-    return;
-  MediaPlayerAndroid* remote_player = GetPlayer(player_id);
-  remote_player->Pause(true);
-  Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(), player_id));
-  Send(new MediaPlayerMsg_DisconnectedFromRemoteDevice(RoutingID(), player_id));
-
-  GetLocalPlayer(player_id)->SeekTo(remote_player->GetCurrentTime());
-  SwapCurrentPlayer(player_id);
-  remote_player->Release();
-  players_playing_remotely_.erase(player_id);
-}
-
-void RemoteMediaPlayerManager::OnRemoteDeviceUnselected(int player_id) {
-  ReplaceRemotePlayerWithLocal(player_id);
-}
-
-void RemoteMediaPlayerManager::OnRemotePlaybackStarted(int player_id) {
-  Send(new MediaPlayerMsg_RemotePlaybackStarted(RoutingID(), player_id));
-}
-
-void RemoteMediaPlayerManager::OnRemotePlaybackFinished(int player_id) {
-  ReplaceRemotePlayerWithLocal(player_id);
-}
-
-void RemoteMediaPlayerManager::OnRouteAvailabilityChanged(
-    int player_id, blink::WebRemotePlaybackAvailability availability) {
-  Send(new MediaPlayerMsg_RemoteRouteAvailabilityChanged(
-      RoutingID(), player_id, availability));
-}
-
-void RemoteMediaPlayerManager::OnCancelledRemotePlaybackRequest(int player_id) {
-  Send(new MediaPlayerMsg_CancelledRemotePlaybackRequest(
-      RoutingID(), player_id));
-}
-
-
-void RemoteMediaPlayerManager::ReleaseFullscreenPlayer(
-    MediaPlayerAndroid* player) {
-  int player_id = player->player_id();
-  // Release the original player's resources, not the current fullscreen player
-  // (which is the remote player).
-  if (IsPlayingRemotely(player_id))
-    GetLocalPlayer(player_id)->Release();
-  else
-    BrowserMediaPlayerManager::ReleaseFullscreenPlayer(player);
-}
-
-void RemoteMediaPlayerManager::OnPlaying(int player_id) {
-  Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(),player_id));
-}
-
-void RemoteMediaPlayerManager::OnPaused(int player_id) {
-  Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(),player_id));
-}
-
-std::vector<std::unique_ptr<MediaPlayerAndroid>>::iterator
-RemoteMediaPlayerManager::GetAlternativePlayer(int player_id) {
-  for (auto it = alternative_players_.begin(); it != alternative_players_.end();
-       ++it) {
-    if ((*it)->player_id() == player_id) {
-      return it;
-    }
-  }
-  return alternative_players_.end();
-}
-
-RemoteMediaPlayerBridge* RemoteMediaPlayerManager::GetRemotePlayer(
-    int player_id) {
-  if (IsPlayingRemotely(player_id))
-    return static_cast<RemoteMediaPlayerBridge*>(GetPlayer(player_id));
-  auto it = GetAlternativePlayer(player_id);
-  if (it == alternative_players_.end())
-    return nullptr;
-  return static_cast<RemoteMediaPlayerBridge*>(it->get());
-}
-
-MediaPlayerAndroid* RemoteMediaPlayerManager::GetLocalPlayer(int player_id) {
-  if (!IsPlayingRemotely(player_id))
-    return GetPlayer(player_id);
-  auto it = GetAlternativePlayer(player_id);
-  if (it == alternative_players_.end())
-    return nullptr;
-  return it->get();
-}
-
-void RemoteMediaPlayerManager::OnMediaMetadataChanged(int player_id,
-                                                      base::TimeDelta duration,
-                                                      int width,
-                                                      int height,
-                                                      bool success) {
-  if (IsPlayingRemotely(player_id)) {
-    MediaPlayerAndroid* local_player = GetLocalPlayer(player_id);
-    Send(new MediaPlayerMsg_MediaMetadataChanged(
-        RoutingID(), player_id, duration, local_player->GetVideoWidth(),
-        local_player->GetVideoHeight(), success));
-  } else {
-    BrowserMediaPlayerManager::OnMediaMetadataChanged(player_id, duration,
-                                                      width, height, success);
-  }
-}
-} // namespace remote_media
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.h b/chrome/browser/media/android/remote/remote_media_player_manager.h
deleted file mode 100644
index 5e7cf887..0000000
--- a/chrome/browser/media/android/remote/remote_media_player_manager.h
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_ANDROID_REMOTE_REMOTE_MEDIA_PLAYER_MANAGER_H_
-#define CHROME_BROWSER_MEDIA_ANDROID_REMOTE_REMOTE_MEDIA_PLAYER_MANAGER_H_
-
-#include <memory>
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-#include "base/macros.h"
-#include "chrome/browser/media/android/remote/remote_media_player_bridge.h"
-#include "content/browser/media/android/browser_media_player_manager.h"
-#include "media/base/android/media_player_android.h"
-
-struct MediaPlayerHostMsg_Initialize_Params;
-
-namespace blink {
-enum class WebRemotePlaybackAvailability;
-}
-
-namespace remote_media {
-
-// media::MediaPlayerManager implementation that allows the user to play media
-// remotely.
-class RemoteMediaPlayerManager : public content::BrowserMediaPlayerManager {
- public:
-  explicit RemoteMediaPlayerManager(
-      content::RenderFrameHost* render_frame_host);
-  ~RemoteMediaPlayerManager() override;
-
-  void OnPlaying(int player_id);
-  void OnPaused(int player_id);
-
-  // Callback to trigger when a remote device has been unselected.
-  void OnRemoteDeviceUnselected(int player_id);
-
-  // Callback to trigger when the video on a remote device starts playing.
-  void OnRemotePlaybackStarted(int player_id);
-
-  // Callback to trigger when the video on a remote device finishes playing.
-  void OnRemotePlaybackFinished(int player_id);
-
-  // Callback to trigger when the availability of remote routes changes.
-  void OnRouteAvailabilityChanged(
-      int player_id, blink::WebRemotePlaybackAvailability availability);
-
-  // Callback to trigger when the device picker dialog was dismissed.
-  void OnCancelledRemotePlaybackRequest(int player_id);
-
-  void OnMediaMetadataChanged(int player_id,
-                              base::TimeDelta duration,
-                              int width,
-                              int height,
-                              bool success) override;
-
-  // Swap which player is currently in use (local or remote).
-  void SwitchToRemotePlayer(int player_id, const std::string& casting_message);
-  void SwitchToLocalPlayer(int player_id);
-
-  // Get the local player for a given player id, whether or not it is currently
-  // playing locally. Will return nullptr if the local player no longer exists.
-  media::MediaPlayerAndroid* GetLocalPlayer(int player_id);
-
- protected:
-  void OnSetPoster(int player_id, const GURL& url) override;
-
-  void ReleaseResources(int player_id) override;
-
- private:
-  // Returns a MediaPlayerAndroid implementation for playing the media remotely.
-  RemoteMediaPlayerBridge* CreateRemoteMediaPlayer(int player_id);
-
-  // Replaces the remote player with the local player this class is holding.
-  // Does nothing if there is no remote player.
-  void ReplaceRemotePlayerWithLocal(int player_id);
-
-  // content::BrowserMediaPlayerManager overrides.
-  void OnStart(int player_id) override;
-  void OnInitialize(
-      const MediaPlayerHostMsg_Initialize_Params& media_player_params) override;
-  void OnDestroyPlayer(int player_id) override;
-  void OnSuspendAndReleaseResources(int player_id) override;
-  void OnRequestRemotePlayback(int player_id) override;
-  void OnRequestRemotePlaybackControl(int player_id) override;
-  void OnRequestRemotePlaybackStop(int player_id) override;
-
-  bool IsPlayingRemotely(int player_id) override;
-
-  void ReleaseFullscreenPlayer(media::MediaPlayerAndroid* player) override;
-
-  // Callback for when the download of poster image is done.
-  void DidDownloadPoster(
-      int player_id,
-      int id,
-      int http_status_code,
-      const GURL& image_url,
-      const std::vector<SkBitmap>& bitmaps,
-      const std::vector<gfx::Size>& original_bitmap_sizes);
-
-  // Return the ID of the tab that's associated with this controller. Returns
-  // -1 in case something goes wrong.
-  int GetTabId();
-
-  // Get the player that is not currently selected
-  std::vector<std::unique_ptr<media::MediaPlayerAndroid>>::iterator
-  GetAlternativePlayer(int player_id);
-
-  // Get the remote player for a given player id, whether or not it is currently
-  // playing remotely.
-  RemoteMediaPlayerBridge* GetRemotePlayer(int player_id);
-
-  bool SwapCurrentPlayer(int player_id);
-
-  void FetchPosterBitmap(int player_id);
-
-  // Contains the alternative players that are not currently in use, i.e. the
-  // remote players for videos that are playing locally, and the local players
-  // for videos that are playing remotely.
-  std::vector<std::unique_ptr<media::MediaPlayerAndroid>> alternative_players_;
-
-  std::set<int> players_playing_remotely_;
-  std::unordered_map<int, GURL> poster_urls_;
-
-  base::WeakPtrFactory<RemoteMediaPlayerManager> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(RemoteMediaPlayerManager);
-};
-
-} // namespace remote_media
-
-#endif  // CHROME_BROWSER_MEDIA_ANDROID_REMOTE_REMOTE_MEDIA_PLAYER_MANAGER_H_
diff --git a/chrome/browser/media/router/discovery/dial/dial_service.cc b/chrome/browser/media/router/discovery/dial/dial_service.cc
index 49ede07..0c27310 100644
--- a/chrome/browser/media/router/discovery/dial/dial_service.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_service.cc
@@ -23,6 +23,7 @@
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/network_service_instance.h"
 #include "net/base/address_family.h"
 #include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
@@ -33,6 +34,7 @@
 #include "net/http/http_util.h"
 #include "net/log/net_log.h"
 #include "net/log/net_log_source.h"
+#include "services/network/public/mojom/network_service.mojom.h"
 #include "url/gurl.h"
 
 #if defined(OS_CHROMEOS)
@@ -151,17 +153,6 @@
   }
   return bind_address_list;
 }
-
-#else
-// Note: This can be called only on a thread that allows IO.
-NetworkInterfaceList GetNetworkList() {
-  NetworkInterfaceList list;
-  bool success =
-      net::GetNetworkList(&list, net::INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES);
-  if (!success)
-    VLOG(1) << "Could not retrieve network list!";
-  return list;
-}
 #endif  // defined(OS_CHROMEOS)
 
 }  // namespace
@@ -442,23 +433,44 @@
     return;
   }
 
-#if defined(OS_CHROMEOS)
   auto task_runner =
       base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI});
+
+#if defined(OS_CHROMEOS)
   task_tracker_.PostTaskAndReplyWithResult(
       task_runner.get(), FROM_HERE,
       base::BindOnce(&GetBestBindAddressOnUIThread),
       base::BindOnce(&DialServiceImpl::DiscoverOnAddresses,
                      base::Unretained(this)));
 #else
-  auto task_runner = base::CreateTaskRunnerWithTraits({base::MayBlock()});
-  task_tracker_.PostTaskAndReplyWithResult(
-      task_runner.get(), FROM_HERE, base::BindOnce(&GetNetworkList),
-      base::BindOnce(&DialServiceImpl::SendNetworkList,
+  task_tracker_.PostTask(
+      task_runner.get(), FROM_HERE,
+      base::BindOnce(&DialServiceImpl::GetNetworkListOnUIThread,
                      base::Unretained(this)));
 #endif
 }
 
+void DialServiceImpl::GetNetworkListOnUIThread() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  content::GetNetworkService()->GetNetworkList(
+      net::INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES,
+      base::BindOnce(&DialServiceImpl::PostSendNetworkList,
+                     weak_ptr_factory_for_ui_.GetWeakPtr()));
+}
+
+void DialServiceImpl::PostSendNetworkList(
+    const base::Optional<net::NetworkInterfaceList>& networks) {
+  if (!networks.has_value())
+    VLOG(1) << "Could not retrieve network list!";
+
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(
+          &DialServiceImpl::SendNetworkList,
+          weak_ptr_factory_for_io_.GetWeakPtr(),
+          networks.has_value() ? *networks : net::NetworkInterfaceList()));
+}
+
 void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   using InterfaceIndexAddressFamily = std::pair<uint32_t, net::AddressFamily>;
diff --git a/chrome/browser/media/router/discovery/dial/dial_service.h b/chrome/browser/media/router/discovery/dial/dial_service.h
index 022bb8b..413ebf9 100644
--- a/chrome/browser/media/router/discovery/dial/dial_service.h
+++ b/chrome/browser/media/router/discovery/dial/dial_service.h
@@ -185,6 +185,13 @@
   // Starts the control flow for one discovery cycle.
   void StartDiscovery();
 
+  // Task to retrieve networks on UI thread.
+  void GetNetworkListOnUIThread();
+
+  // Callback invoked to send retrieved networks on IO thread.
+  void PostSendNetworkList(
+      const base::Optional<net::NetworkInterfaceList>& networks);
+
   // For each network interface in |list|, finds all unqiue IPv4 network
   // interfaces and call |DiscoverOnAddresses()| with their IP addresses.
   void SendNetworkList(const net::NetworkInterfaceList& list);
@@ -262,6 +269,12 @@
 
   base::CancelableTaskTracker task_tracker_;
 
+  // WeakPrtFactory for WeakPtrs that are invalidated on UI thread.
+  base::WeakPtrFactory<DialServiceImpl> weak_ptr_factory_for_ui_{this};
+
+  // WeakPrtFactory for WeakPtrs that are invalidated on IO thread.
+  base::WeakPtrFactory<DialServiceImpl> weak_ptr_factory_for_io_{this};
+
   friend class DialServiceTest;
   FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestSendMultipleRequests);
   FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestMultipleNetworkInterfaces);
diff --git a/chrome/browser/net/disk_cache_dir_policy_handler.cc b/chrome/browser/net/disk_cache_dir_policy_handler.cc
index 192b093..4719c1c 100644
--- a/chrome/browser/net/disk_cache_dir_policy_handler.cc
+++ b/chrome/browser/net/disk_cache_dir_policy_handler.cc
@@ -27,8 +27,7 @@
   if (value && value->GetAsString(&string_value)) {
     base::FilePath::StringType expanded_value =
         policy::path_parser::ExpandPathVariables(string_value);
-    prefs->SetValue(prefs::kDiskCacheDir,
-                    std::make_unique<base::Value>(expanded_value));
+    prefs->SetValue(prefs::kDiskCacheDir, base::Value(expanded_value));
   }
 }
 
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 85c7022..b8d8e49 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -73,11 +73,24 @@
 #include "ui/gfx/geometry/point.h"
 
 using base::ASCIIToUTF16;
+using base::Feature;
 using testing::_;
 using testing::ElementsAre;
 
+namespace password_manager {
 namespace {
 
+void SetNewParsingForSaving(base::test::ScopedFeatureList* scoped_feature_list,
+                            bool enabled) {
+  std::vector<Feature> features = {features::kNewPasswordFormParsing,
+                                   features::kNewPasswordFormParsingForSaving};
+
+  std::vector<Feature> enabled_features;
+  std::vector<Feature> disabled_features;
+  (enabled ? enabled_features : disabled_features) = std::move(features);
+  scoped_feature_list->InitWithFeatures(enabled_features, disabled_features);
+}
+
 class PasswordManagerBrowserTest : public PasswordManagerBrowserTestBase {
  public:
   PasswordManagerBrowserTest() {
@@ -87,6 +100,7 @@
     password_manager::NewPasswordFormManager::
         set_wait_for_server_predictions_for_filling(false);
   }
+
   ~PasswordManagerBrowserTest() override = default;
 };
 
@@ -226,10 +240,6 @@
   observer.Wait();
 }
 
-}  // namespace
-
-namespace password_manager {
-
 // Actual tests ---------------------------------------------------------------
 
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForNormalSubmit) {
@@ -272,25 +282,32 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
-                       NoPromptIfPasswordFormManagerDestroyed) {
-  NavigateToFile("/password/password_form.html");
-  // Simulate the Credential Manager API essentially destroying all the
-  // PasswordFormManager instances.
-  ChromePasswordManagerClient::FromWebContents(WebContents())
-      ->NotifyStorePasswordCalled();
+                       NoPromptAfterCredentialsAPIPasswordStore) {
+  for (bool use_new_parsing_for_saving : {false, true}) {
+    SCOPED_TRACE(testing::Message() << "use_new_parsing_for_saving = "
+                                    << use_new_parsing_for_saving);
+    base::test::ScopedFeatureList scoped_feature_list;
+    SetNewParsingForSaving(&scoped_feature_list, use_new_parsing_for_saving);
+    NavigateToFile("/password/password_form.html");
+    // Simulate the Credential Manager API function store() is called and
+    // PasswordManager instance is notified about that.
+    ChromePasswordManagerClient::FromWebContents(WebContents())
+        ->NotifyStorePasswordCalled();
 
-  // Fill a form and submit through a <input type="submit"> button. The renderer
-  // should not send "PasswordFormsParsed" messages after the page was loaded.
-  NavigationObserver observer(WebContents());
-  std::string fill_and_submit =
-      "document.getElementById('username_field').value = 'temp';"
-      "document.getElementById('password_field').value = 'random';"
-      "document.getElementById('input_submit_button').click()";
-  ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit));
-  observer.Wait();
-  std::unique_ptr<BubbleObserver> prompt_observer(
-      new BubbleObserver(WebContents()));
-  EXPECT_FALSE(prompt_observer->IsSavePromptShownAutomatically());
+    // Fill a form and submit through a <input type="submit"> button. The
+    // renderer should not send "PasswordFormsParsed" messages after the page
+    // was loaded.
+    NavigationObserver observer(WebContents());
+    std::string fill_and_submit =
+        "document.getElementById('username_field').value = 'temp';"
+        "document.getElementById('password_field').value = 'random';"
+        "document.getElementById('input_submit_button').click()";
+    ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit));
+    observer.Wait();
+    std::unique_ptr<BubbleObserver> prompt_observer(
+        new BubbleObserver(WebContents()));
+    EXPECT_FALSE(prompt_observer->IsSavePromptShownAutomatically());
+  }
 }
 
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
@@ -3992,4 +4009,5 @@
   WaitForElementValue("password_field", "pw");
 }
 
+}  // namespace
 }  // namespace password_manager
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index ed33119f..f8aa3b9 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -1783,7 +1783,11 @@
 // and even occluded.
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
                        PageVisibilityEventsFired) {
-  LoadTabAndEnterPictureInPicture(browser());
+  GURL test_page_url = ui_test_utils::GetTestUrl(
+      base::FilePath(base::FilePath::kCurrentDirectory),
+      base::FilePath(
+          FILE_PATH_LITERAL("media/picture-in-picture/window-size.html")));
+  ui_test_utils::NavigateToURL(browser(), test_page_url);
 
   content::WebContents* active_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -1815,7 +1819,7 @@
 }
 
 // Check that page visibility API events are fired even when video is in
-// Picture-in-Picture.
+// Picture-in-Picture and video playback is not disrupted.
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
                        PageVisibilityEventsFiredWhenPictureInPicture) {
   LoadTabAndEnterPictureInPicture(browser());
@@ -1824,11 +1828,12 @@
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_NE(nullptr, active_web_contents);
 
-  // Enter Picture-in-Picture manually.
-  bool result = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "enterPictureInPicture();", &result));
-  EXPECT_TRUE(result);
+  ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();"));
+
+  bool is_paused = true;
+  ASSERT_TRUE(ExecuteScriptAndExtractBool(active_web_contents, "isPaused();",
+                                          &is_paused));
+  EXPECT_FALSE(is_paused);
 
   ASSERT_TRUE(content::ExecuteScript(active_web_contents,
                                      "addVisibilityChangeEventListener();"));
@@ -1840,11 +1845,14 @@
             content::TitleWatcher(active_web_contents, expected_title)
                 .WaitAndGetTitle());
 
-  // Check that the video is still in Picture-in-Picture.
+  // Check that the video is still in Picture-in-Picture and playing.
   bool in_picture_in_picture = false;
   ASSERT_TRUE(ExecuteScriptAndExtractBool(
       active_web_contents, "isInPictureInPicture();", &in_picture_in_picture));
   EXPECT_TRUE(in_picture_in_picture);
+  ASSERT_TRUE(ExecuteScriptAndExtractBool(active_web_contents, "isPaused();",
+                                          &is_paused));
+  EXPECT_FALSE(is_paused);
 
   // Show page and check that the document visibility is visible.
   active_web_contents->WasShown();
@@ -1853,10 +1861,13 @@
             content::TitleWatcher(active_web_contents, expected_title)
                 .WaitAndGetTitle());
 
-  // Check that the video is still in Picture-in-Picture.
+  // Check that the video is still in Picture-in-Picture and playing.
   ASSERT_TRUE(ExecuteScriptAndExtractBool(
       active_web_contents, "isInPictureInPicture();", &in_picture_in_picture));
   EXPECT_TRUE(in_picture_in_picture);
+  ASSERT_TRUE(ExecuteScriptAndExtractBool(active_web_contents, "isPaused();",
+                                          &is_paused));
+  EXPECT_FALSE(is_paused);
 
   // Occlude page and check that the document visibility is hidden.
   active_web_contents->WasOccluded();
@@ -1865,10 +1876,13 @@
             content::TitleWatcher(active_web_contents, expected_title)
                 .WaitAndGetTitle());
 
-  // Check that the video is still in Picture-in-Picture.
+  // Check that the video is still in Picture-in-Picture and playing.
   ASSERT_TRUE(ExecuteScriptAndExtractBool(
       active_web_contents, "isInPictureInPicture();", &in_picture_in_picture));
   EXPECT_TRUE(in_picture_in_picture);
+  ASSERT_TRUE(ExecuteScriptAndExtractBool(active_web_contents, "isPaused();",
+                                          &is_paused));
+  EXPECT_FALSE(is_paused);
 }
 
 class MediaSessionPictureInPictureWindowControllerBrowserTest
diff --git a/chrome/browser/plugins/plugin_policy_handler.cc b/chrome/browser/plugins/plugin_policy_handler.cc
index bd3c955..ffd2e82 100644
--- a/chrome/browser/plugins/plugin_policy_handler.cc
+++ b/chrome/browser/plugins/plugin_policy_handler.cc
@@ -59,14 +59,14 @@
                             plugin)) &&
         !policies.GetValue(policy::key::kAlwaysOpenPdfExternally)) {
       prefs->SetValue(prefs::kPluginsAlwaysOpenPdfExternally,
-                      std::make_unique<base::Value>(disable_pdf_plugin));
+                      base::Value(disable_pdf_plugin));
     }
     if ((base::MatchPattern(
              PluginMetadata::kAdobeFlashPlayerGroupName, plugin) ||
          base::MatchPattern(content::kFlashPluginName, plugin)) &&
         !policies.GetValue(policy::key::kDefaultPluginsSetting)) {
       prefs->SetValue(prefs::kManagedDefaultPluginsSetting,
-                      std::make_unique<base::Value>(flash_content_setting));
+                      base::Value(flash_content_setting));
     }
   }
 }
diff --git a/chrome/browser/profiling_host/memlog_browsertest.cc b/chrome/browser/profiling_host/memlog_browsertest.cc
index 09f81a1..f3ffae1 100644
--- a/chrome/browser/profiling_host/memlog_browsertest.cc
+++ b/chrome/browser/profiling_host/memlog_browsertest.cc
@@ -34,6 +34,7 @@
 struct TestParam {
   Mode mode;
   mojom::StackMode stack_mode;
+  bool stream_samples;
   bool start_profiling_with_command_line_flag;
   bool should_sample;
   bool sample_everything;
@@ -92,6 +93,7 @@
 IN_PROC_BROWSER_TEST_P(MemlogBrowserTest, MAYBE_EndToEnd) {
   LOG(INFO) << "Memlog mode: " << static_cast<int>(GetParam().mode);
   LOG(INFO) << "Memlog stack mode: " << static_cast<int>(GetParam().stack_mode);
+  LOG(INFO) << "Stream samples: " << GetParam().stream_samples;
   LOG(INFO) << "Started via command line flag: "
             << GetParam().start_profiling_with_command_line_flag;
   LOG(INFO) << "Should sample: " << GetParam().should_sample;
@@ -100,6 +102,7 @@
   TestDriver::Options options;
   options.mode = GetParam().mode;
   options.stack_mode = GetParam().stack_mode;
+  options.stream_samples = GetParam().stream_samples;
   options.profiling_already_started =
       GetParam().start_profiling_with_command_line_flag;
   options.should_sample = GetParam().should_sample;
@@ -123,54 +126,60 @@
   stack_modes.push_back(mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES);
   stack_modes.push_back(mojom::StackMode::PSEUDO);
 
-  for (const auto& mode : dynamic_start_modes) {
-    for (const auto& stack_mode : stack_modes) {
-      params.push_back(
-          {mode, stack_mode, false /* start_profiling_with_command_line_flag */,
-           false /* should_sample */, false /* sample_everything*/});
+  for (bool stream_samples : (bool[]){true, false}) {
+    for (const auto& mode : dynamic_start_modes) {
+      for (const auto& stack_mode : stack_modes) {
+        params.push_back({mode, stack_mode, stream_samples,
+                          false /* start_profiling_with_command_line_flag */,
+                          false /* should_sample */,
+                          false /* sample_everything*/});
+      }
     }
-  }
 
 // For unknown reasons, renderer profiling has become flaky on ChromeOS. This is
 // likely happening because the renderers are never being given the signal to
 // start profiling. It's unclear why this happens. https://crbug.com/843843.
 // https://crbug.com/843467.
 #if !defined(OS_CHROMEOS)
-  // Non-browser processes must be profiled with a command line flag, since
-  // otherwise, profiling will start after the relevant processes have been
-  // created, thus that process will be not be profiled.
-  std::vector<Mode> command_line_start_modes;
-  command_line_start_modes.push_back(Mode::kAll);
-  command_line_start_modes.push_back(Mode::kAllRenderers);
-  for (const auto& mode : command_line_start_modes) {
-    for (const auto& stack_mode : stack_modes) {
-      params.push_back(
-          {mode, stack_mode, true /* start_profiling_with_command_line_flag */,
-           false /* should_sample */, false /* sample_everything*/});
+    // Non-browser processes must be profiled with a command line flag, since
+    // otherwise, profiling will start after the relevant processes have been
+    // created, thus that process will be not be profiled.
+    std::vector<Mode> command_line_start_modes;
+    command_line_start_modes.push_back(Mode::kAll);
+    command_line_start_modes.push_back(Mode::kAllRenderers);
+    for (const auto& mode : command_line_start_modes) {
+      for (const auto& stack_mode : stack_modes) {
+        params.push_back({mode, stack_mode, stream_samples,
+                          true /* start_profiling_with_command_line_flag */,
+                          false /* should_sample */,
+                          false /* sample_everything*/});
+      }
     }
-  }
 #endif  // defined(OS_CHROMEOS)
 
-  // Test sampling all allocations.
-  params.push_back({Mode::kBrowser, mojom::StackMode::NATIVE_WITH_THREAD_NAMES,
-                    false /* start_profiling_with_command_line_flag */,
-                    true /* should_sample */, true /* sample_everything*/});
+    // Test sampling all allocations.
+    params.push_back(
+        {Mode::kBrowser, mojom::StackMode::NATIVE_WITH_THREAD_NAMES,
+         stream_samples, false /* start_profiling_with_command_line_flag */,
+         true /* should_sample */, true /* sample_everything*/});
 
-  // Test sampling some allocations.
-  params.push_back({Mode::kBrowser, mojom::StackMode::PSEUDO,
-                    false /* start_profiling_with_command_line_flag */,
-                    true /* should_sample */, false /* sample_everything*/});
+    // Test sampling some allocations.
+    params.push_back({Mode::kBrowser, mojom::StackMode::PSEUDO, stream_samples,
+                      false /* start_profiling_with_command_line_flag */,
+                      true /* should_sample */, false /* sample_everything*/});
 
-  // Test thread names for native profiling.
-  params.push_back(
-      {Mode::kBrowser, mojom::StackMode::NATIVE_WITH_THREAD_NAMES, false});
+    // Test thread names for native profiling.
+    params.push_back({Mode::kBrowser,
+                      mojom::StackMode::NATIVE_WITH_THREAD_NAMES,
+                      stream_samples, false});
 
-  // Profile all utility processes and the browser process. The main goal is to
-  // check that there is no deadlock in the profiling process.
-  params.push_back({Mode::kUtilityAndBrowser,
-                    mojom::StackMode::NATIVE_WITH_THREAD_NAMES,
-                    false /* start_profiling_with_command_line_flag */,
-                    true /* should_sample */, false /* sample_everything*/});
+    // Profile all utility processes and the browser process. The main goal is
+    // to check that there is no deadlock in the profiling process.
+    params.push_back(
+        {Mode::kUtilityAndBrowser, mojom::StackMode::NATIVE_WITH_THREAD_NAMES,
+         stream_samples, false /* start_profiling_with_command_line_flag */,
+         true /* should_sample */, false /* sample_everything*/});
+  }
   return params;
 }
 
diff --git a/chrome/browser/resources/interventions_internals/index.html b/chrome/browser/resources/interventions_internals/index.html
index f8d0ad4..dba1b625 100644
--- a/chrome/browser/resources/interventions_internals/index.html
+++ b/chrome/browser/resources/interventions_internals/index.html
@@ -103,6 +103,10 @@
         Estimated effective connection type:
         <span id="nqe-type">N/A</span>
       </div>
+      <div id="nqe-slow-page-threshold">
+        Slow page maximum threshold:
+        <span id="max-intervention-type">N/A</span>
+      </div>
       <div id="nqe-logs">
         <div class="table-name">Network Quality Change Log</div>
         <table id="nqe-logs-table">
diff --git a/chrome/browser/resources/interventions_internals/index.js b/chrome/browser/resources/interventions_internals/index.js
index 41ee656..c25c1ef 100644
--- a/chrome/browser/resources/interventions_internals/index.js
+++ b/chrome/browser/resources/interventions_internals/index.js
@@ -555,12 +555,18 @@
    *
    * @override
    * @param {string} type The string representation of estimated ECT.
+   * @param {string} maxInterventionType The string representation of the
+   * session's maximum ECT threshold for interventions.
    */
-  onEffectiveConnectionTypeChanged: function(type) {
+  updateEffectiveConnectionType: function(type, maxInterventionType) {
     // Change the current ECT.
     const ectType = $('nqe-type');
     ectType.textContent = type;
 
+    // Set the session maximum ECT for interventions.
+    const maxInterventionEctType = $('max-intervention-type');
+    maxInterventionEctType.textContent = maxInterventionType;
+
     const now = getTimeFormat(Date.now());
 
     // Log ECT changed event to ECT change log.
diff --git a/chrome/browser/resources/settings/autofill_page/password_list_item.html b/chrome/browser/resources/settings/autofill_page/password_list_item.html
index acf1bc8..cd795d3a 100644
--- a/chrome/browser/resources/settings/autofill_page/password_list_item.html
+++ b/chrome/browser/resources/settings/autofill_page/password_list_item.html
@@ -23,10 +23,10 @@
 
       #username,
       #password {
+        color: inherit;
         /* Since #password is an input element this is necessary to prevent
          * Chrome from using the operating system's font instead of the Material
-         * Design font.
-         */
+         * Design font. TODO(dbeam): why not font: inherit? */
         font-family: inherit;
         font-size: inherit;
         line-height: inherit;
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_shared_css.html b/chrome/browser/resources/settings/autofill_page/passwords_shared_css.html
index 9c26b98d..05f5b0c 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_shared_css.html
+++ b/chrome/browser/resources/settings/autofill_page/passwords_shared_css.html
@@ -18,7 +18,7 @@
       }
 
       .website-column > a {
-        color: var(--google-grey-900);
+        color: var(--cr-primary-text-color);
       }
 
       .username-column {
diff --git a/chrome/browser/resources/settings/privacy_page/personalization_options.html b/chrome/browser/resources/settings/privacy_page/personalization_options.html
index 8ec53b8..9df16c8 100644
--- a/chrome/browser/resources/settings/privacy_page/personalization_options.html
+++ b/chrome/browser/resources/settings/privacy_page/personalization_options.html
@@ -28,12 +28,6 @@
         label="$i18n{searchSuggestPref}"
         sub-label="$i18n{searchSuggestPrefDesc}">
     </settings-toggle-button>
-    <settings-toggle-button hidden="[[!pageVisibility.networkPrediction]]"
-        pref="{{prefs.net.network_prediction_options}}"
-        label="$i18n{networkPredictionEnabled}"
-        sub-label="$i18n{networkPredictionEnabledDesc}"
-        numeric-unchecked-value="[[networkPredictionEnum_.NEVER]]">
-    </settings-toggle-button>
     <settings-toggle-button pref="{{prefs.alternate_error_pages.enabled}}"
         label="$i18n{linkDoctorPref}"
         sub-label="$i18n{linkDoctorPrefDesc}">
diff --git a/chrome/browser/resources/settings/privacy_page/personalization_options.js b/chrome/browser/resources/settings/privacy_page/personalization_options.js
index fcdf4ec1..c6ffda1 100644
--- a/chrome/browser/resources/settings/privacy_page/personalization_options.js
+++ b/chrome/browser/resources/settings/privacy_page/personalization_options.js
@@ -9,17 +9,6 @@
  */
 (function() {
 
-/**
- * Must be kept in sync with the C++ enum of the same name.
- * @enum {number}
- */
-const NetworkPredictionOptions = {
-  ALWAYS: 0,
-  WIFI_ONLY: 1,
-  NEVER: 2,
-  DEFAULT: 1,
-};
-
 Polymer({
   is: 'settings-personalization-options',
 
@@ -39,17 +28,6 @@
      */
     pageVisibility: Object,
 
-    /**
-     * Used for HTML bindings. This is defined as a property rather than within
-     * the ready callback, because the value needs to be available before
-     * local DOM initialization - otherwise, the toggle has unexpected behavior.
-     * @private
-     */
-    networkPredictionEnum_: {
-      type: Object,
-      value: NetworkPredictionOptions,
-    },
-
     unifiedConsentEnabled: Boolean,
 
     /** @type {settings.SyncStatus} */
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 23119518..5b2311c9 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -119,6 +119,12 @@
             label="$i18n{canMakePaymentToggleLabel}"
             pref="{{prefs.payments.can_make_payment_enabled}}">
         </settings-toggle-button>
+        <settings-toggle-button hidden="[[!pageVisibility.networkPrediction]]"
+            pref="{{prefs.net.network_prediction_options}}"
+            label="$i18n{networkPredictionEnabled}"
+            sub-label="$i18n{networkPredictionEnabledDesc}"
+            numeric-unchecked-value="[[networkPredictionUncheckedValue_]]">
+        </settings-toggle-button>
 <if expr="chromeos">
         <settings-toggle-button
             pref="{{prefs.cros.device.attestation_for_content_protection_enabled}}"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js
index e379410..25f9482 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -17,6 +17,17 @@
  */
 (function() {
 
+/**
+ * Must be kept in sync with the C++ enum of the same name.
+ * @enum {number}
+ */
+const NetworkPredictionOptions = {
+  ALWAYS: 0,
+  WIFI_ONLY: 1,
+  NEVER: 2,
+  DEFAULT: 1,
+};
+
 Polymer({
   is: 'settings-privacy-page',
 
@@ -64,6 +75,17 @@
       value: false,
     },
 
+    /**
+     * Used for HTML bindings. This is defined as a property rather than within
+     * the ready callback, because the value needs to be available before
+     * local DOM initialization - otherwise, the toggle has unexpected behavior.
+     * @private
+     */
+    networkPredictionUncheckedValue_: {
+      type: Number,
+      value: NetworkPredictionOptions.NEVER,
+    },
+
     /** @private */
     enableSafeBrowsingSubresourceFilter_: {
       type: Boolean,
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html
index d383b13..52486aca 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -328,7 +328,7 @@
       }
 
       .column-header {
-        color: var(--google-grey-refresh-700);
+        color: var(--cr-secondary-text-color);
         font-size: inherit;
         font-weight: 400;
       }
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index c99f1ed..e36a368 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
+#include "chrome/browser/ui/dark_mode_observer.h"
 #include "chrome/browser/ui/webui/favicon_source.h"
 #include "chrome/browser/ui/webui/theme_source.h"
 #include "chrome/common/chrome_paths.h"
@@ -50,7 +51,6 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/url_data_source.h"
 #include "ui/gfx/color_utils.h"
-#include "ui/native_theme/native_theme_observer.h"
 
 namespace {
 
@@ -147,48 +147,6 @@
   base::RepeatingCallback<void(bool)> callback_;
 };
 
-// Keeps track of any changes to system dark mode and notifies InstantService if
-// dark mode has been changed. Use this to check if dark mode is enabled.
-class InstantService::DarkModeHandler : public ui::NativeThemeObserver {
- public:
-  explicit DarkModeHandler(ui::NativeTheme* theme,
-                           base::RepeatingCallback<void(bool)> callback)
-      : theme_(theme), callback_(std::move(callback)), observer_(this) {
-    using_dark_mode_ = IsDarkModeEnabled();
-    observer_.Add(theme_);
-  }
-
-  bool IsDarkModeEnabled() { return theme_->SystemDarkModeEnabled(); }
-
-  void SetThemeForTesting(ui::NativeTheme* theme) {
-    observer_.RemoveAll();
-
-    theme_ = theme;
-    using_dark_mode_ = IsDarkModeEnabled();
-    observer_.Add(theme_);
-  }
-
- private:
-  // ui::NativeThemeObserver:
-  void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override {
-    DCHECK_EQ(observed_theme, theme_);
-
-    bool using_dark_mode = IsDarkModeEnabled();
-    if (using_dark_mode == using_dark_mode_)
-      return;
-
-    using_dark_mode_ = using_dark_mode;
-    callback_.Run(using_dark_mode_);
-  }
-
-  // The theme to query/watch for changes.
-  ui::NativeTheme* theme_;
-  // Whether or not the theme is using dark mode.
-  bool using_dark_mode_;
-  base::RepeatingCallback<void(bool)> callback_;
-  ScopedObserver<ui::NativeTheme, DarkModeHandler> observer_;
-};
-
 InstantService::InstantService(Profile* profile)
     : profile_(profile),
       pref_service_(profile_->GetPrefs()),
@@ -242,10 +200,7 @@
     }
   }
 
-  dark_mode_handler_ = std::make_unique<DarkModeHandler>(
-      ui::NativeTheme::GetInstanceForNativeUi(),
-      base::BindRepeating(&InstantService::OnDarkModeChanged,
-                          weak_ptr_factory_.GetWeakPtr()));
+  CreateDarkModeObserver(ui::NativeTheme::GetInstanceForNativeUi());
 
   background_service_ = NtpBackgroundServiceFactory::GetForProfile(profile_);
 
@@ -271,7 +226,7 @@
   pref_change_registrar_.Add(
       prefs::kNtpCustomBackgroundDict,
       base::BindRepeating(&InstantService::UpdateBackgroundFromSync,
-                          base::Unretained(this)));
+                          weak_ptr_factory_.GetWeakPtr()));
 }
 
 InstantService::~InstantService() = default;
@@ -450,8 +405,7 @@
 }
 
 void InstantService::SetDarkModeThemeForTesting(ui::NativeTheme* theme) {
-  if (dark_mode_handler_)
-    dark_mode_handler_->SetThemeForTesting(theme);
+  CreateDarkModeObserver(theme);
 }
 
 void InstantService::Shutdown() {
@@ -585,7 +539,7 @@
   theme_info_->using_default_theme =
       theme_service->UsingDefaultTheme() || theme_service->UsingSystemTheme();
 
-  theme_info_->using_dark_mode = dark_mode_handler_->IsDarkModeEnabled();
+  theme_info_->using_dark_mode = dark_mode_observer_->InDarkMode();
 
   // Get theme colors.
   const ui::ThemeProvider& theme_provider =
@@ -792,6 +746,13 @@
   background_service_->AddValidBackdropUrlForTesting(url);
 }
 
+void InstantService::CreateDarkModeObserver(ui::NativeTheme* theme) {
+  dark_mode_observer_ = std::make_unique<DarkModeObserver>(
+      theme, base::BindRepeating(&InstantService::OnDarkModeChanged,
+                                 weak_ptr_factory_.GetWeakPtr()));
+  dark_mode_observer_->Start();
+}
+
 // static
 void InstantService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterDictionaryPref(
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index 0db2b10..7bf4bdd 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -32,6 +32,7 @@
 #error "Instant is only used on desktop";
 #endif
 
+class DarkModeObserver;
 class InstantIOContext;
 class InstantServiceObserver;
 class NtpBackgroundService;
@@ -148,8 +149,6 @@
  private:
   class SearchProviderObserver;
 
-  class DarkModeHandler;
-
   friend class InstantExtendedTest;
   friend class InstantUnitTestBase;
 
@@ -213,6 +212,8 @@
   // chrome-search://local-ntp/background.jpg
   void SetBackgroundToLocalResource();
 
+  void CreateDarkModeObserver(ui::NativeTheme* theme);
+
   Profile* const profile_;
 
   // The process ids associated with Instant processes.
@@ -236,13 +237,13 @@
   // Keeps track of any changes in search engine provider. May be null.
   std::unique_ptr<SearchProviderObserver> search_provider_observer_;
 
-  // Keeps track of any changes to system dark mode.
-  std::unique_ptr<DarkModeHandler> dark_mode_handler_;
-
   PrefChangeRegistrar pref_change_registrar_;
 
   PrefService* pref_service_;
 
+  // Keeps track of any changes to system dark mode.
+  std::unique_ptr<DarkModeObserver> dark_mode_observer_;
+
   NtpBackgroundService* background_service_;
 
   base::WeakPtrFactory<InstantService> weak_ptr_factory_;
diff --git a/chrome/browser/supervised_user/supervised_user_pref_store.cc b/chrome/browser/supervised_user/supervised_user_pref_store.cc
index e645ddf..3621961 100644
--- a/chrome/browser/supervised_user/supervised_user_pref_store.cc
+++ b/chrome/browser/supervised_user/supervised_user_pref_store.cc
@@ -147,7 +147,7 @@
     for (const auto& entry : kSupervisedUserSettingsPrefMapping) {
       const base::Value* value = NULL;
       if (settings->GetWithoutPathExpansion(entry.settings_name, &value))
-        prefs_->SetValue(entry.pref_name, value->CreateDeepCopy());
+        prefs_->SetValue(entry.pref_name, value->Clone());
     }
 
     // Manually set preferences that aren't direct copies of the settings value.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 83cc87a..c209374 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -108,6 +108,8 @@
     "confirm_bubble.h",
     "crypto_module_password_dialog.h",
     "cryptuiapi_shim.h",
+    "dark_mode_observer.cc",
+    "dark_mode_observer.h",
     "enterprise_startup_dialog.h",
     "find_bar/find_bar.h",
     "find_bar/find_bar_state.h",
diff --git a/chrome/browser/ui/dark_mode_observer.cc b/chrome/browser/ui/dark_mode_observer.cc
new file mode 100644
index 0000000..342d00f
--- /dev/null
+++ b/chrome/browser/ui/dark_mode_observer.cc
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/dark_mode_observer.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/native_theme/native_theme_observer.h"
+
+DarkModeObserver::DarkModeObserver(
+    ui::NativeTheme* theme,
+    const base::RepeatingCallback<void(bool)>& callback)
+    : theme_(theme),
+      callback_(callback),
+      in_dark_mode_(theme_->SystemDarkModeEnabled()),
+      theme_observer_(this) {}
+
+DarkModeObserver::~DarkModeObserver() = default;
+
+void DarkModeObserver::Start() {
+  RunCallbackIfChanged();
+  theme_observer_.Add(theme_);
+}
+
+void DarkModeObserver::Stop() {
+  theme_observer_.RemoveAll();
+}
+
+void DarkModeObserver::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
+  DCHECK_EQ(observed_theme, theme_);
+  RunCallbackIfChanged();
+}
+
+void DarkModeObserver::RunCallbackIfChanged() {
+  bool in_dark_mode = theme_->SystemDarkModeEnabled();
+  if (in_dark_mode_ == in_dark_mode)
+    return;
+  in_dark_mode_ = in_dark_mode;
+  callback_.Run(in_dark_mode_);
+}
diff --git a/chrome/browser/ui/dark_mode_observer.h b/chrome/browser/ui/dark_mode_observer.h
new file mode 100644
index 0000000..2f81334
--- /dev/null
+++ b/chrome/browser/ui/dark_mode_observer.h
@@ -0,0 +1,50 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_DARK_MODE_OBSERVER_H_
+#define CHROME_BROWSER_UI_DARK_MODE_OBSERVER_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/scoped_observer.h"
+#include "ui/native_theme/native_theme_observer.h"
+
+class DarkModeObserver : public ui::NativeThemeObserver {
+ public:
+  // Observe |theme| for changes and run |callback| if detected.
+  DarkModeObserver(ui::NativeTheme* theme,
+                   const base::RepeatingCallback<void(bool)>& callback);
+
+  ~DarkModeObserver() override;
+
+  // Observe |theme| for changes in dark mode. |callback_| may be immediately
+  // run if |theme_->SystemDarkModeEnabled()| has changed since construction or
+  // last time |Stop()| was called.
+  void Start();
+
+  // Stop observing |theme|. |callback_| will never be called after stopping.
+  void Stop();
+
+  bool InDarkMode() const { return in_dark_mode_; }
+
+ private:
+  // ui::NativeThemeObserver:
+  void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
+
+  // Run |callback_| if |theme_->SystemDarkModeEnabled()| != |in_dark_mode_|.
+  void RunCallbackIfChanged();
+
+  // The theme to query/watch for changes.
+  ui::NativeTheme* const theme_;
+
+  base::RepeatingCallback<void(bool)> callback_;
+
+  bool in_dark_mode_;
+
+  ScopedObserver<ui::NativeTheme, DarkModeObserver> theme_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(DarkModeObserver);
+};
+
+#endif  // CHROME_BROWSER_UI_DARK_MODE_OBSERVER_H_
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index 74bda8d..5f5d5527 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -297,9 +297,13 @@
     }
 
     // Update the window size to adhere to the aspect ratio.
+    gfx::Size min_size = min_size_;
+    gfx::Size max_size = max_size_;
+    views::WindowResizeUtils::SizeMinMaxToAspectRatio(aspect_ratio, &min_size,
+                                                      &max_size);
     gfx::Rect window_rect(GetBounds().origin(), window_size);
     views::WindowResizeUtils::SizeRectToAspectRatio(
-        hit_test, aspect_ratio, min_size_, max_size_, &window_rect);
+        hit_test, aspect_ratio, min_size, max_size, &window_rect);
     window_size.SetSize(window_rect.width(), window_rect.height());
 
     UpdateLayerBoundsWithLetterboxing(window_size);
@@ -440,10 +444,12 @@
   GetControlsScrimLayer()->SetVisible(is_visible);
   GetControlsParentLayer()->SetVisible(is_visible);
   GetBackToTabControlsLayer()->SetVisible(is_visible);
-  GetSkipAdControlsLayer()->SetVisible(is_visible && show_skip_ad_button_);
-  skip_ad_controls_view_->SetEnabled(is_visible && show_skip_ad_button_);
   GetCloseControlsLayer()->SetVisible(is_visible);
 
+  // We need to do more than usual visibility change because otherwise control
+  // is accessible via accessibility tools.
+  skip_ad_controls_view_->ToggleVisibility(is_visible && show_skip_ad_button_);
+
 #if defined(OS_CHROMEOS)
   GetResizeHandleLayer()->SetVisible(is_visible);
 #endif
diff --git a/chrome/browser/ui/views/overlay/skip_ad_label_button.cc b/chrome/browser/ui/views/overlay/skip_ad_label_button.cc
index 2d15883..bd1d9952 100644
--- a/chrome/browser/ui/views/overlay/skip_ad_label_button.cc
+++ b/chrome/browser/ui/views/overlay/skip_ad_label_button.cc
@@ -47,4 +47,11 @@
       size.height() - kSkipAdButtonHeight - kSkipAdButtonMarginBottom));
 }
 
+void SkipAdLabelButton::ToggleVisibility(bool is_visible) {
+  layer()->SetVisible(is_visible);
+  SetEnabled(is_visible);
+  SetSize(is_visible ? gfx::Size(kSkipAdButtonWidth, kSkipAdButtonHeight)
+                     : gfx::Size());
+}
+
 }  // namespace views
diff --git a/chrome/browser/ui/views/overlay/skip_ad_label_button.h b/chrome/browser/ui/views/overlay/skip_ad_label_button.h
index a3d545d..1b17b9a 100644
--- a/chrome/browser/ui/views/overlay/skip_ad_label_button.h
+++ b/chrome/browser/ui/views/overlay/skip_ad_label_button.h
@@ -19,6 +19,9 @@
   // Sets the position of itself with an offset from the given window size.
   void SetPosition(const gfx::Size& size);
 
+  // Toggle visibility.
+  void ToggleVisibility(bool is_visible);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SkipAdLabelButton);
 };
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
index 720807c..df7a297 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -205,9 +205,14 @@
 
 std::unique_ptr<views::Background>
 PaymentHandlerWebFlowViewController::GetHeaderBackground() {
-  if (!web_contents())
-    return PaymentRequestSheetController::GetHeaderBackground();
-  return views::CreateSolidBackground(web_contents()->GetThemeColor());
+  auto default_header_background =
+      PaymentRequestSheetController::GetHeaderBackground();
+  if (web_contents()) {
+    return views::CreateSolidBackground(color_utils::GetResultingPaintColor(
+        web_contents()->GetThemeColor(),
+        default_header_background->get_color()));
+  }
+  return default_header_background;
 }
 
 bool PaymentHandlerWebFlowViewController::GetSheetId(DialogViewID* sheet_id) {
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
index 23ea172..489db17 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
@@ -27,6 +27,7 @@
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/text_constants.h"
+#include "ui/native_theme/native_theme.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/image_view.h"
@@ -135,8 +136,10 @@
         provider->GetDistanceMetric(views::DISTANCE_RELATED_LABEL_HORIZONTAL)));
     views::ImageView* icon = new views::ImageView();
     const gfx::VectorIcon& vector_id = requests[index]->GetIconId();
-    icon->SetImage(gfx::CreateVectorIcon(vector_id, kPermissionIconSize,
-                                         gfx::kChromeIconGrey));
+    const SkColor icon_color = icon->GetNativeTheme()->GetSystemColor(
+        ui::NativeTheme::kColorId_DefaultIconColor);
+    icon->SetImage(
+        gfx::CreateVectorIcon(vector_id, kPermissionIconSize, icon_color));
     label_container->AddChildView(icon);
     views::Label* label =
         new views::Label(requests.at(index)->GetMessageTextFragment());
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index f70a5e2f..40649db 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -887,8 +887,12 @@
   if (test_expects_complete_login_)
     SubmitLoginFormForTest();
 
-  if (LoginDisplayHost::default_host())
+  if (LoginDisplayHost::default_host()) {
     LoginDisplayHost::default_host()->OnGaiaScreenReady();
+  } else {
+    // Used to debug crbug.com/902315. Feel free to remove after that is fixed.
+    LOG(ERROR) << "HandleGaiaUIReady: There is no LoginDisplayHost";
+  }
 }
 
 void GaiaScreenHandler::HandleUpdateOobeDialogSize(int width, int height) {
diff --git a/chrome/browser/ui/webui/dark_mode_handler.cc b/chrome/browser/ui/webui/dark_mode_handler.cc
index 91ffae2..cf5e50ad 100644
--- a/chrome/browser/ui/webui/dark_mode_handler.cc
+++ b/chrome/browser/ui/webui/dark_mode_handler.cc
@@ -14,27 +14,20 @@
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "ui/native_theme/native_theme.h"
-#include "ui/native_theme/native_theme_observer.h"
-
-namespace {
-
-using ui::NativeTheme;
-
-}  // namespace
 
 DarkModeHandler::~DarkModeHandler() {}
 
 // static
 void DarkModeHandler::Initialize(content::WebUI* web_ui,
                                  content::WebUIDataSource* source) {
-  InitializeInternal(web_ui, source, NativeTheme::GetInstanceForNativeUi(),
+  InitializeInternal(web_ui, source, ui::NativeTheme::GetInstanceForNativeUi(),
                      Profile::FromWebUI(web_ui));
 }
 
 // static
 void DarkModeHandler::InitializeInternal(content::WebUI* web_ui,
                                          content::WebUIDataSource* source,
-                                         NativeTheme* theme,
+                                         ui::NativeTheme* theme,
                                          Profile* profile) {
   auto handler = base::WrapUnique(new DarkModeHandler(theme, profile));
   source->AddLocalizedStrings(*handler->GetDataSourceUpdate());
@@ -42,11 +35,14 @@
   web_ui->AddMessageHandler(std::move(handler));
 }
 
-DarkModeHandler::DarkModeHandler(NativeTheme* theme, Profile* profile)
-    : theme_(theme),
-      profile_(profile),
-      using_dark_(IsDarkModeEnabled()),
-      observer_(this) {}
+DarkModeHandler::DarkModeHandler(ui::NativeTheme* theme, Profile* profile)
+    : profile_(profile),
+      dark_mode_observer_(
+          theme,
+          base::BindRepeating(&DarkModeHandler::OnDarkModeChanged,
+                              base::Unretained(this))) {
+  dark_mode_observer_.Start();
+}
 
 void DarkModeHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
@@ -55,39 +51,27 @@
                           base::Unretained(this)));
 }
 
-void DarkModeHandler::OnNativeThemeUpdated(NativeTheme* observed_theme) {
-  DCHECK_EQ(observed_theme, theme_);
-  NotifyIfChanged();
-}
-
-void DarkModeHandler::OnJavascriptDisallowed() {
-  observer_.RemoveAll();
-}
-
 void DarkModeHandler::HandleObserveDarkMode(const base::ListValue* /*args*/) {
   AllowJavascript();
-  observer_.Add(theme_);
 }
 
-bool DarkModeHandler::IsDarkModeEnabled() const {
+bool DarkModeHandler::UseDarkMode() const {
   return base::FeatureList::IsEnabled(features::kWebUIDarkMode) &&
-         theme_->SystemDarkModeEnabled();
+         dark_mode_observer_.InDarkMode();
 }
 
 std::unique_ptr<base::DictionaryValue> DarkModeHandler::GetDataSourceUpdate()
     const {
   auto update = std::make_unique<base::DictionaryValue>();
-  update->SetKey("dark", base::Value(using_dark_ ? "dark" : ""));
-  update->SetKey("darkMode", base::Value(using_dark_));
+  bool use_dark_mode = UseDarkMode();
+  update->SetKey("dark", base::Value(use_dark_mode ? "dark" : ""));
+  update->SetKey("darkMode", base::Value(use_dark_mode));
   return update;
 }
 
-void DarkModeHandler::NotifyIfChanged() {
-  bool use_dark = IsDarkModeEnabled();
-  if (use_dark == using_dark_)
-    return;
-  using_dark_ = use_dark;
-  FireWebUIListener("dark-mode-changed", base::Value(use_dark));
+void DarkModeHandler::OnDarkModeChanged(bool /*dark_mode*/) {
   content::WebUIDataSource::Update(profile_, source_name_,
                                    GetDataSourceUpdate());
+  if (IsJavascriptAllowed())
+    FireWebUIListener("dark-mode-changed", base::Value(UseDarkMode()));
 }
diff --git a/chrome/browser/ui/webui/dark_mode_handler.h b/chrome/browser/ui/webui/dark_mode_handler.h
index 4eafcadd..6d42a71 100644
--- a/chrome/browser/ui/webui/dark_mode_handler.h
+++ b/chrome/browser/ui/webui/dark_mode_handler.h
@@ -8,11 +8,12 @@
 #include <memory>
 #include <string>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "chrome/browser/ui/dark_mode_observer.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "ui/native_theme/native_theme.h"
-#include "ui/native_theme/native_theme_observer.h"
 
 namespace base {
 class ListValue;
@@ -29,8 +30,7 @@
 
 class Profile;
 
-class DarkModeHandler : public content::WebUIMessageHandler,
-                        public ui::NativeThemeObserver {
+class DarkModeHandler : public content::WebUIMessageHandler {
  public:
   ~DarkModeHandler() override;
 
@@ -55,34 +55,22 @@
  private:
   // content::WebUIMessageHandler:
   void RegisterMessages() override;
-  void OnJavascriptDisallowed() override;
-
-  // ui::NativeThemeObserver:
-  void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
 
   // Handles the "observeDarkMode" message. No arguments. Protected for testing.
   void HandleObserveDarkMode(const base::ListValue* args);
 
+  bool UseDarkMode() const;
+
   // Generates a dictionary with "dark" and "darkMode" i18n keys based on
   // |using_dark_|. Called initialize and on each change for notifications.
   std::unique_ptr<base::DictionaryValue> GetDataSourceUpdate() const;
 
-  // Whether the feature is enabled and the system is in dark mode.
-  bool IsDarkModeEnabled() const;
-
-  // Fire a webui listener notification if dark mode actually changed.
-  void NotifyIfChanged();
-
-  // The theme to query/watch for changes. Injected for testing.
-  ui::NativeTheme* const theme_;
+  void OnDarkModeChanged(bool dark_mode);
 
   // Profile to update data sources on. Injected for testing.
   Profile* const profile_;
 
-  // Whether or not this page is using dark mode.
-  bool using_dark_;
-
-  ScopedObserver<ui::NativeTheme, DarkModeHandler> observer_;
+  DarkModeObserver dark_mode_observer_;
 
   // Populated if feature is enabled.
   std::string source_name_;
diff --git a/chrome/browser/ui/webui/dark_mode_handler_unittest.cc b/chrome/browser/ui/webui/dark_mode_handler_unittest.cc
index e19432f..e9dca146 100644
--- a/chrome/browser/ui/webui/dark_mode_handler_unittest.cc
+++ b/chrome/browser/ui/webui/dark_mode_handler_unittest.cc
@@ -173,3 +173,44 @@
   ASSERT_TRUE(web_ui()->call_data()[0]->arg2()->is_bool());
   EXPECT_TRUE(web_ui()->call_data()[0]->arg2()->GetBool());
 }
+
+TEST_F(DarkModeHandlerTest, DarkModeChangeBeforeJsAllowed) {
+  features()->InitAndEnableFeature(features::kWebUIDarkMode);
+  theme()->SetDarkMode(false);
+
+  InitializeHandler();
+
+  EXPECT_EQ(web_ui()->GetHandlersForTesting()->size(), 1u);
+  EXPECT_EQ(web_ui()->call_data().size(), 0u);
+  EXPECT_FALSE(IsSourceDark());
+
+  theme()->SetDarkMode(true);
+  theme()->NotifyObservers();
+
+  EXPECT_EQ(web_ui()->call_data().size(), 0u);
+
+  bundle()->RunUntilIdle();
+  EXPECT_TRUE(IsSourceDark());
+}
+
+TEST_F(DarkModeHandlerTest, DarkModeChangeWhileJsDisallowed) {
+  features()->InitAndEnableFeature(features::kWebUIDarkMode);
+  theme()->SetDarkMode(false);
+
+  InitializeHandler();
+
+  EXPECT_EQ(web_ui()->GetHandlersForTesting()->size(), 1u);
+  EXPECT_EQ(web_ui()->call_data().size(), 0u);
+  EXPECT_FALSE(IsSourceDark());
+
+  web_ui()->HandleReceivedMessage("observeDarkMode", /*args=*/nullptr);
+  web_ui()->GetHandlersForTesting()->front()->DisallowJavascript();
+
+  theme()->SetDarkMode(true);
+  theme()->NotifyObservers();
+
+  EXPECT_EQ(web_ui()->call_data().size(), 0u);
+
+  bundle()->RunUntilIdle();
+  EXPECT_TRUE(IsSourceDark());
+}
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom b/chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom
index 0b39e90..7e520156 100644
--- a/chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom
+++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom
@@ -88,9 +88,11 @@
   OnBlacklistCleared(int64 time);
 
   // Notify the page on the new estimated effective connection type is |type|.
-  // This is called by InterventionsInternalsPageHandler when the estimate
-  // network quality changes.
-  OnEffectiveConnectionTypeChanged(string type);
+  // Also reports the session's maximum intervention effective connection type
+  // |max_intervention_type| for slow pages. This method is called by
+  // InterventionsInternalsPageHandler when the estimate network quality
+  // changes.
+  UpdateEffectiveConnectionType(string type, string max_intervention_type);
 
   // Notify the page on whether the blacklist decision is considered or ignored.
   // This method is called by InterventionsInternalsPageHandler when the status
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc
index e8700f43..a9542d86 100644
--- a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc
+++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc
@@ -150,7 +150,10 @@
     return;
   }
   std::string ect_name = net::GetNameForEffectiveConnectionType(type);
-  page_->OnEffectiveConnectionTypeChanged(ect_name);
+  std::string max_intervention_ect_name =
+      net::GetNameForEffectiveConnectionType(
+          previews::params::GetSessionMaxECTThreshold());
+  page_->UpdateEffectiveConnectionType(ect_name, max_intervention_ect_name);
 
   // Log change ECT event.
   previews::PreviewsLogger::MessageLog message(
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
index b655c5d..6c16d57 100644
--- a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
@@ -158,7 +158,9 @@
   void OnBlacklistCleared(int64_t time) override {
     blacklist_cleared_time_ = time;
   }
-  void OnEffectiveConnectionTypeChanged(const std::string& type) override {
+  void UpdateEffectiveConnectionType(
+      const std::string& type,
+      const std::string& max_intervention_type) override {
     // Ignore.
     // TODO(thanhdle): Add integration test to test behavior of the pipeline end
     // to end. crbug.com/777936
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 1cc6bd5..ff4ce635 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -38,6 +38,7 @@
 #include "base/version.h"
 #include "base/win/registry.h"
 #include "base/win/windows_version.h"
+#include "build/build_config.h"
 #include "chrome/install_static/install_details.h"
 #include "chrome/install_static/install_modes.h"
 #include "chrome/install_static/install_util.h"
@@ -481,7 +482,13 @@
 }
 
 bool IsProcessorSupported() {
+#if defined(ARCH_CPU_X86_FAMILY)
   return base::CPU().has_sse2();
+#elif defined(ARCH_CPU_ARM64)
+  return true;
+#else
+#error Port
+#endif
 }
 
 base::string16 GetCommandKey(const wchar_t* name) {
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.cc b/chrome/test/chromedriver/chrome/chrome_impl.cc
index 9fa588f..657f2f2 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_impl.cc
@@ -319,7 +319,7 @@
   if (status.IsError())
     return status;
 
-  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1000));
   std::string state;
   if (!bounds->GetString("windowState", &state))
     return Status(kOk);
diff --git a/chrome/test/data/webui/interventions_internals_browsertest.js b/chrome/test/data/webui/interventions_internals_browsertest.js
index 240d11d..db92c50 100644
--- a/chrome/test/data/webui/interventions_internals_browsertest.js
+++ b/chrome/test/data/webui/interventions_internals_browsertest.js
@@ -601,7 +601,7 @@
     let pageImpl = new InterventionsInternalPageImpl(null);
     let ectTypes = ['type1', 'type2', 'type3'];
     ectTypes.forEach((type) => {
-      pageImpl.onEffectiveConnectionTypeChanged(type);
+      pageImpl.updateEffectiveConnectionType(type, 'max');
       let actual = $('nqe-type').textContent;
       expectEquals(type, actual);
     });
diff --git a/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js b/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js
index 2f2c17b..08a3c30 100644
--- a/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js
+++ b/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js
@@ -78,23 +78,36 @@
 function onRequestSession() {
   switch (sessionTypeToRequest) {
     case sessionTypes.IMMERSIVE:
-      console.info('Requesting immersive session');
+      console.info('Requesting immersive VR session');
       navigator.xr.requestSession({mode: 'immersive-vr'}).then( (session) => {
-        console.info('Immersive session request succeeded');
+        console.info('Immersive VR session request succeeded');
         sessionInfos[sessionTypes.IMMERSIVE].currentSession = session;
         onSessionStarted(session);
       }, (error) => {
-        console.info('Immersive session request rejected with: ' + error);
+        console.info('Immersive VR session request rejected with: ' + error);
       });
       break;
     case sessionTypes.AR:
-      console.info('Requesting AR session');
+      console.info('Requesting Immersive AR session');
       navigator.xr.requestSession({mode: 'immersive-ar'}).then((session) => {
-        console.info('AR session request succeeded');
+        console.info('Immersive AR session request succeeded');
         sessionInfos[sessionTypes.AR].currentSession = session;
         onSessionStarted(session);
       }, (error) => {
-        console.info('AR session request rejected with: ' + error);
+        console.info('Immersive AR session request rejected with: ' + error);
+        console.info('Attempting to fall back to legacy AR mode');
+        let sessionOptions = {
+          mode: 'legacy-inline-ar',
+          outputContext: webglCanvas.getContext('xrpresent'),
+        }
+        navigator.xr.requestSession(sessionOptions).then(
+            (session) => {
+          console.info('Legacy AR session request succeeded');
+          sessionInfos[sessionTypes.AR].currentSession = session;
+          onSessionStarted(session);
+        }, (error) => {
+          console.info('Legacy AR session request rejected with: ' + error);
+        });
       });
       break;
     default:
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h
index 4e5802b..da4eca0 100644
--- a/chromecast/browser/cast_content_browser_client.h
+++ b/chromecast/browser/cast_content_browser_client.h
@@ -216,6 +216,10 @@
       service_manager::mojom::InterfaceProvider* host_interfaces);
 #endif  // BUILDFLAG(USE_CHROMECAST_CDMS)
 
+  CastNetworkContexts* cast_network_contexts() {
+    return cast_network_contexts_.get();
+  }
+
  protected:
   explicit CastContentBrowserClient(
       CastFeatureListCreator* cast_feature_list_creator);
diff --git a/components/cronet/native/test/url_request_test.cc b/components/cronet/native/test/url_request_test.cc
index 46ff1284..574a875 100644
--- a/components/cronet/native/test/url_request_test.cc
+++ b/components/cronet/native/test/url_request_test.cc
@@ -993,13 +993,7 @@
   cronet::TestServer::ReleaseBigDataURL();
 }
 
-// https://crbug.com/921713 Flaky crash on Fuchsia.
-#if defined(OS_FUCHSIA)
-#define MAYBE_GetStatus DISABLED_GetStatus
-#else
-#define MAYBE_GetStatus GetStatus
-#endif
-TEST_P(UrlRequestTest, MAYBE_GetStatus) {
+TEST_P(UrlRequestTest, GetStatus) {
   Cronet_EnginePtr engine = cronet::test::CreateTestEngine(0);
   Cronet_UrlRequestPtr request = Cronet_UrlRequest_Create();
   Cronet_UrlRequestParamsPtr request_params = Cronet_UrlRequestParams_Create();
@@ -1050,7 +1044,7 @@
     // final callbacks.
     GetRequestStatus(request, &test_callback);
     test_callback.WaitForNextStep();
-  } while (!test_callback.IsDone());
+  } while (!Cronet_UrlRequest_IsDone(request));
 
   EXPECT_EQ(Cronet_UrlRequestStatusListener_Status_INVALID,
             GetRequestStatus(request, &test_callback));
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index eb7ed1db..731402f 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -23,6 +23,8 @@
     "data_source_observer.h",
     "display.cc",
     "display.h",
+    "frame_sink_resource_manager.cc",
+    "frame_sink_resource_manager.h",
     "keyboard_delegate.h",
     "keyboard_device_configuration_delegate.h",
     "keyboard_observer.h",
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc
index c0cbd56..b6e39931 100644
--- a/components/exo/buffer.cc
+++ b/components/exo/buffer.cc
@@ -21,7 +21,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/traced_value.h"
-#include "components/exo/layer_tree_frame_sink_holder.h"
+#include "components/exo/frame_sink_resource_manager.h"
 #include "components/exo/wm_helper.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/resources/resource_format.h"
@@ -412,7 +412,7 @@
 Buffer::~Buffer() {}
 
 bool Buffer::ProduceTransferableResource(
-    LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder,
+    FrameSinkResourceManager* resource_manager,
     bool secure_output_only,
     viz::TransferableResource* resource) {
   TRACE_EVENT1("exo", "Buffer::ProduceTransferableResource", "buffer_id",
@@ -437,7 +437,7 @@
     return false;
   }
 
-  resource->id = layer_tree_frame_sink_holder->AllocateResourceId();
+  resource->id = resource_manager->AllocateResourceId();
   resource->format = viz::RGBA_8888;
   resource->filter = GL_LINEAR;
   resource->size = gpu_memory_buffer_->GetSize();
@@ -471,7 +471,7 @@
 
     // The contents texture will be released when no longer used by the
     // compositor.
-    layer_tree_frame_sink_holder->SetResourceReleaseCallback(
+    resource_manager->SetResourceReleaseCallback(
         resource->id,
         base::BindOnce(&Buffer::Texture::ReleaseTexImage,
                        base::Unretained(contents_texture),
@@ -501,7 +501,7 @@
 
   // The mailbox texture will be released when no longer used by the
   // compositor.
-  layer_tree_frame_sink_holder->SetResourceReleaseCallback(
+  resource_manager->SetResourceReleaseCallback(
       resource->id,
       base::BindOnce(&Buffer::Texture::Release, base::Unretained(texture),
                      base::Bind(&Buffer::ReleaseTexture, AsWeakPtr(),
diff --git a/components/exo/buffer.h b/components/exo/buffer.h
index 92fc03f..9fbc01e 100644
--- a/components/exo/buffer.h
+++ b/components/exo/buffer.h
@@ -17,7 +17,7 @@
 
 namespace exo {
 
-class LayerTreeFrameSinkHolder;
+class FrameSinkResourceManager;
 
 // This class provides the content for a Surface. The mechanism by which a
 // client provides and updates the contents is the responsibility of the client
@@ -51,10 +51,9 @@
   // buffer. Returns a release callback on success. The release callback should
   // be called before a new texture mailbox can be acquired unless
   // |non_client_usage| is true.
-  bool ProduceTransferableResource(
-      LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder,
-      bool secure_output_only,
-      viz::TransferableResource* resource);
+  bool ProduceTransferableResource(FrameSinkResourceManager* resource_manager,
+                                   bool secure_output_only,
+                                   viz::TransferableResource* resource);
 
   // This should be called when the buffer is attached to a Surface.
   void OnAttach();
diff --git a/components/exo/buffer_unittest.cc b/components/exo/buffer_unittest.cc
index a4e137ad..3e8e934 100644
--- a/components/exo/buffer_unittest.cc
+++ b/components/exo/buffer_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "components/exo/buffer.h"
+#include "components/exo/frame_sink_resource_manager.h"
 #include "components/exo/surface_tree_host.h"
 #include "components/exo/test/exo_test_base.h"
 #include "components/exo/test/exo_test_helper.h"
@@ -65,8 +66,8 @@
   buffer->OnAttach();
   viz::TransferableResource resource;
   // Produce a transferable resource for the contents of the buffer.
-  bool rv =
-      buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
+  bool rv = buffer->ProduceTransferableResource(
+      frame_sink_holder->resource_manager(), false, &resource);
   ASSERT_TRUE(rv);
 
   // Release buffer.
@@ -97,8 +98,8 @@
   buffer->OnAttach();
   // Acquire a texture transferable resource for the contents of the buffer.
   viz::TransferableResource resource;
-  bool rv =
-      buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
+  bool rv = buffer->ProduceTransferableResource(
+      frame_sink_holder->resource_manager(), false, &resource);
   ASSERT_TRUE(rv);
 
   scoped_refptr<viz::ContextProvider> context_provider =
@@ -122,8 +123,8 @@
   // Producing a new texture transferable resource for the contents of the
   // buffer.
   viz::TransferableResource new_resource;
-  rv = buffer->ProduceTransferableResource(frame_sink_holder, false,
-                                           &new_resource);
+  rv = buffer->ProduceTransferableResource(
+      frame_sink_holder->resource_manager(), false, &new_resource);
   ASSERT_TRUE(rv);
   buffer->OnDetach();
 
@@ -150,8 +151,8 @@
   buffer->OnAttach();
   // Acquire a texture transferable resource for the contents of the buffer.
   viz::TransferableResource resource;
-  bool rv =
-      buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
+  bool rv = buffer->ProduceTransferableResource(
+      frame_sink_holder->resource_manager(), false, &resource);
   ASSERT_TRUE(rv);
 
   static_cast<ui::InProcessContextFactory*>(GetAuraEnv()->context_factory())
@@ -178,8 +179,8 @@
   buffer->OnAttach();
   viz::TransferableResource resource;
   // Produce a transferable resource for the contents of the buffer.
-  bool rv =
-      buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
+  bool rv = buffer->ProduceTransferableResource(
+      frame_sink_holder->resource_manager(), false, &resource);
   ASSERT_TRUE(rv);
 
   // Submit frame with resource.
@@ -231,8 +232,8 @@
   buffer->OnAttach();
   viz::TransferableResource resource;
   // Produce a transferable resource for the contents of the buffer.
-  bool rv =
-      buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
+  bool rv = buffer->ProduceTransferableResource(
+      frame_sink_holder->resource_manager(), false, &resource);
   ASSERT_TRUE(rv);
 
   // Submit frame with resource.
diff --git a/components/exo/frame_sink_resource_manager.cc b/components/exo/frame_sink_resource_manager.cc
new file mode 100644
index 0000000..90be3a6
--- /dev/null
+++ b/components/exo/frame_sink_resource_manager.cc
@@ -0,0 +1,52 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/frame_sink_resource_manager.h"
+
+#include <utility>
+
+#include "base/stl_util.h"
+
+namespace exo {
+
+FrameSinkResourceManager::FrameSinkResourceManager() {}
+FrameSinkResourceManager::~FrameSinkResourceManager() {
+  ClearAllCallbacks();
+}
+
+bool FrameSinkResourceManager::HasReleaseCallbackForResource(
+    viz::ResourceId id) {
+  return release_callbacks_.find(id) != release_callbacks_.end();
+}
+void FrameSinkResourceManager::SetResourceReleaseCallback(
+    viz::ResourceId id,
+    viz::ReleaseCallback callback) {
+  DCHECK(!callback.is_null());
+  release_callbacks_[id] = std::move(callback);
+}
+int FrameSinkResourceManager::AllocateResourceId() {
+  return next_resource_id_++;
+}
+
+bool FrameSinkResourceManager::HasNoCallbacks() const {
+  return release_callbacks_.empty();
+}
+
+void FrameSinkResourceManager::ReclaimResource(
+    const viz::ReturnedResource& resource) {
+  auto it = release_callbacks_.find(resource.id);
+  DCHECK(it != release_callbacks_.end());
+  if (it != release_callbacks_.end()) {
+    std::move(it->second).Run(resource.sync_token, resource.lost);
+    release_callbacks_.erase(it);
+  }
+}
+
+void FrameSinkResourceManager::ClearAllCallbacks() {
+  for (auto& callback : release_callbacks_)
+    std::move(callback.second).Run(gpu::SyncToken(), true /* lost */);
+  release_callbacks_.clear();
+}
+
+}  // namespace exo
diff --git a/components/exo/frame_sink_resource_manager.h b/components/exo/frame_sink_resource_manager.h
new file mode 100644
index 0000000..c220408
--- /dev/null
+++ b/components/exo/frame_sink_resource_manager.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_EXO_FRAME_SINK_RESOURCE_MANAGER_H_
+#define COMPONENTS_EXO_FRAME_SINK_RESOURCE_MANAGER_H_
+
+#include "base/containers/flat_map.h"
+#include "components/viz/common/resources/release_callback.h"
+#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/common/resources/returned_resource.h"
+
+namespace exo {
+
+// This class manages the resource IDs and active resource callbacks suitable
+// for implementing a frame sink.
+class FrameSinkResourceManager {
+ public:
+  FrameSinkResourceManager();
+  ~FrameSinkResourceManager();
+
+  bool HasReleaseCallbackForResource(viz::ResourceId id);
+  void SetResourceReleaseCallback(viz::ResourceId id,
+                                  viz::ReleaseCallback callback);
+  int AllocateResourceId();
+
+  bool HasNoCallbacks() const;
+  void ReclaimResource(const viz::ReturnedResource& resource);
+  void ClearAllCallbacks();
+
+ private:
+  // A collection of callbacks used to release resources.
+  using ResourceReleaseCallbackMap =
+      base::flat_map<viz::ResourceId, viz::ReleaseCallback>;
+  ResourceReleaseCallbackMap release_callbacks_;
+
+  // The next resource id the buffer is attached to.
+  int next_resource_id_ = 1;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameSinkResourceManager);
+};
+
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_FRAME_SINK_RESOURCE_MANAGER_H_
diff --git a/components/exo/layer_tree_frame_sink_holder.cc b/components/exo/layer_tree_frame_sink_holder.cc
index 3ee6654..c2230202 100644
--- a/components/exo/layer_tree_frame_sink_holder.cc
+++ b/components/exo/layer_tree_frame_sink_holder.cc
@@ -29,9 +29,6 @@
   if (frame_sink_)
     frame_sink_->DetachFromClient();
 
-  for (auto& callback : release_callbacks_)
-    std::move(callback.second).Run(gpu::SyncToken(), true /* lost */);
-
   if (lifetime_manager_)
     lifetime_manager_->RemoveObserver(this);
 }
@@ -68,7 +65,7 @@
 
   // Delete sink holder immediately if not waiting for resources to be
   // reclaimed.
-  if (holder->release_callbacks_.empty())
+  if (holder->resource_manager_.HasNoCallbacks())
     return;
 
   WMHelper::LifetimeManager* lifetime_manager =
@@ -102,22 +99,6 @@
   frame_sink_->DidNotProduceFrame(ack);
 }
 
-bool LayerTreeFrameSinkHolder::HasReleaseCallbackForResource(
-    viz::ResourceId id) {
-  return release_callbacks_.find(id) != release_callbacks_.end();
-}
-
-void LayerTreeFrameSinkHolder::SetResourceReleaseCallback(
-    viz::ResourceId id,
-    viz::ReleaseCallback callback) {
-  DCHECK(!callback.is_null());
-  release_callbacks_[id] = std::move(callback);
-}
-
-int LayerTreeFrameSinkHolder::AllocateResourceId() {
-  return next_resource_id_++;
-}
-
 base::WeakPtr<LayerTreeFrameSinkHolder> LayerTreeFrameSinkHolder::GetWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
@@ -138,15 +119,10 @@
     if (base::ContainsValue(last_frame_resources_, resource.id)) {
       continue;
     }
-    auto it = release_callbacks_.find(resource.id);
-    DCHECK(it != release_callbacks_.end());
-    if (it != release_callbacks_.end()) {
-      std::move(it->second).Run(resource.sync_token, resource.lost);
-      release_callbacks_.erase(it);
-    }
+    resource_manager_.ReclaimResource(resource);
   }
 
-  if (lifetime_manager_ && release_callbacks_.empty())
+  if (lifetime_manager_ && resource_manager_.HasNoCallbacks())
     ScheduleDelete();
 }
 
@@ -164,9 +140,7 @@
 
 void LayerTreeFrameSinkHolder::DidLoseLayerTreeFrameSink() {
   last_frame_resources_.clear();
-  for (auto& callback : release_callbacks_)
-    std::move(callback.second).Run(gpu::SyncToken(), true /* lost */);
-  release_callbacks_.clear();
+  resource_manager_.ClearAllCallbacks();
 
   if (lifetime_manager_)
     ScheduleDelete();
diff --git a/components/exo/layer_tree_frame_sink_holder.h b/components/exo/layer_tree_frame_sink_holder.h
index c6645a8..7d9f727 100644
--- a/components/exo/layer_tree_frame_sink_holder.h
+++ b/components/exo/layer_tree_frame_sink_holder.h
@@ -9,6 +9,7 @@
 
 #include "base/containers/flat_map.h"
 #include "cc/trees/layer_tree_frame_sink_client.h"
+#include "components/exo/frame_sink_resource_manager.h"
 #include "components/exo/wm_helper.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/resources/release_callback.h"
@@ -40,12 +41,10 @@
   void SubmitCompositorFrame(viz::CompositorFrame frame);
   void DidNotProduceFrame(const viz::BeginFrameAck& ack);
 
-  bool HasReleaseCallbackForResource(viz::ResourceId id);
-  void SetResourceReleaseCallback(viz::ResourceId id,
-                                  viz::ReleaseCallback callback);
-  int AllocateResourceId();
   base::WeakPtr<LayerTreeFrameSinkHolder> GetWeakPtr();
 
+  FrameSinkResourceManager* resource_manager() { return &resource_manager_; }
+
   // Overridden from cc::LayerTreeFrameSinkClient:
   void SetBeginFrameSource(viz::BeginFrameSource* source) override {}
   base::Optional<viz::HitTestRegionList> BuildHitTestData() override;
@@ -73,16 +72,10 @@
   // WMHelper::LifetimeManager::Observer:
   void OnDestroyed() override;
 
-  // A collection of callbacks used to release resources.
-  using ResourceReleaseCallbackMap =
-      base::flat_map<viz::ResourceId, viz::ReleaseCallback>;
-  ResourceReleaseCallbackMap release_callbacks_;
-
   SurfaceTreeHost* surface_tree_host_;
   std::unique_ptr<cc::LayerTreeFrameSink> frame_sink_;
 
-  // The next resource id the buffer is attached to.
-  int next_resource_id_ = 1;
+  FrameSinkResourceManager resource_manager_;
 
   gfx::Size last_frame_size_in_pixels_;
   float last_frame_device_scale_factor_ = 1.0f;
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc
index 26b129e..0b18079 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -251,6 +251,11 @@
     }
     case ui::ET_SCROLL: {
       ui::ScrollEvent* scroll_event = static_cast<ui::ScrollEvent*>(event);
+
+      // Scrolling with 3+ fingers should not be handled since it will be used
+      // to trigger overview mode.
+      if (scroll_event->finger_count() >= 3)
+        break;
       delegate_->OnPointerScroll(
           event->time_stamp(),
           gfx::Vector2dF(scroll_event->x_offset(), scroll_event->y_offset()),
diff --git a/components/exo/pointer_unittest.cc b/components/exo/pointer_unittest.cc
index 1ee3d4e..2b7a8bb 100644
--- a/components/exo/pointer_unittest.cc
+++ b/components/exo/pointer_unittest.cc
@@ -570,6 +570,41 @@
   pointer.reset();
 }
 
+TEST_F(MAYBE_PointerTest, OnPointerScrollWithThreeFinger) {
+  std::unique_ptr<Surface> surface(new Surface);
+  std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+  gfx::Size buffer_size(10, 10);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  MockPointerDelegate delegate;
+  std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
+  ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+  gfx::Point location = surface->window()->GetBoundsInScreen().origin();
+
+  EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
+      .WillRepeatedly(testing::Return(true));
+  EXPECT_CALL(delegate, OnPointerFrame()).Times(2);
+
+  EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
+  generator.MoveMouseTo(location);
+
+  {
+    // Expect no scroll.
+    testing::InSequence sequence;
+    EXPECT_CALL(delegate, OnPointerScrollStop(testing::_));
+  }
+
+  // Three fingers scroll.
+  generator.ScrollSequence(location, base::TimeDelta(), 1, 1, 1,
+                           3 /* num_fingers */);
+
+  EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
+  pointer.reset();
+}
+
 TEST_F(MAYBE_PointerTest, OnPointerScrollDiscrete) {
   std::unique_ptr<Surface> surface(new Surface);
   std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index ac487b2..1817c3e3 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/public/cpp/shell_window_ids.h"
 #include "base/callback_helpers.h"
 #include "base/containers/adapters.h"
 #include "base/logging.h"
@@ -13,8 +14,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/traced_value.h"
-#include "cc/trees/layer_tree_frame_sink.h"
 #include "components/exo/buffer.h"
+#include "components/exo/frame_sink_resource_manager.h"
 #include "components/exo/shell_surface_util.h"
 #include "components/exo/surface_delegate.h"
 #include "components/exo/surface_observer.h"
@@ -128,6 +129,15 @@
     return ui::CursorType::kNull;
   }
   int GetNonClientComponent(const gfx::Point& point) const override {
+    views::Widget* widget =
+        views::Widget::GetTopLevelWidgetForNativeView(surface_->window());
+    if (widget &&
+        widget->GetNativeView()->parent()->id() ==
+            ash::kShellWindowId_DefaultContainer &&
+        surface_->HitTest(point)) {
+      return HTCLIENT;
+    }
+
     return HTNOWHERE;
   }
   bool ShouldDescendIntoChildForEventHandling(
@@ -659,7 +669,7 @@
 void Surface::AppendSurfaceHierarchyContentsToFrame(
     const gfx::Point& origin,
     float device_scale_factor,
-    LayerTreeFrameSinkHolder* frame_sink_holder,
+    FrameSinkResourceManager* resource_manager,
     viz::CompositorFrame* frame) {
   // The top most sub-surface is at the front of the RenderPass's quad_list,
   // so we need composite sub-surface in reversed order.
@@ -669,17 +679,16 @@
     // decendents.
     sub_surface->AppendSurfaceHierarchyContentsToFrame(
         origin + sub_surface_entry.second.OffsetFromOrigin(),
-        device_scale_factor, frame_sink_holder, frame);
+        device_scale_factor, resource_manager, frame);
   }
 
   if (needs_update_resource_)
-    UpdateResource(frame_sink_holder);
+    UpdateResource(resource_manager);
 
   AppendContentsToFrame(origin, device_scale_factor, frame);
 
-  DCHECK(
-      !current_resource_.id ||
-      frame_sink_holder->HasReleaseCallbackForResource(current_resource_.id));
+  DCHECK(!current_resource_.id ||
+         resource_manager->HasReleaseCallbackForResource(current_resource_.id));
 }
 
 bool Surface::IsSynchronized() const {
@@ -818,12 +827,12 @@
   buffer_ = buffer;
 }
 
-void Surface::UpdateResource(LayerTreeFrameSinkHolder* frame_sink_holder) {
+void Surface::UpdateResource(FrameSinkResourceManager* resource_manager) {
   DCHECK(needs_update_resource_);
   needs_update_resource_ = false;
   if (current_buffer_.buffer()) {
     if (current_buffer_.buffer()->ProduceTransferableResource(
-            frame_sink_holder, state_.only_visible_on_secure_output,
+            resource_manager, state_.only_visible_on_secure_output,
             &current_resource_)) {
       current_resource_has_alpha_ =
           FormatHasAlpha(current_buffer_.buffer()->GetFormat());
diff --git a/components/exo/surface.h b/components/exo/surface.h
index 57893f1..5b78010 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -39,7 +39,7 @@
 
 namespace exo {
 class Buffer;
-class LayerTreeFrameSinkHolder;
+class FrameSinkResourceManager;
 class SurfaceObserver;
 class Surface;
 
@@ -176,7 +176,7 @@
   void AppendSurfaceHierarchyContentsToFrame(
       const gfx::Point& origin,
       float device_scale_factor,
-      LayerTreeFrameSinkHolder* frame_sink_holder,
+      FrameSinkResourceManager* resource_manager,
       viz::CompositorFrame* frame);
 
   // Returns true if surface is in synchronized mode.
@@ -288,7 +288,7 @@
   // contents of the attached buffer (or id 0, if no buffer is attached).
   // UpdateSurface must be called afterwards to ensure the release callback
   // will be called.
-  void UpdateResource(LayerTreeFrameSinkHolder* frame_sink_holder);
+  void UpdateResource(FrameSinkResourceManager* resource_manager);
 
   // Updates buffer_transform_ to match the current buffer parameters.
   void UpdateBufferTransform(bool y_invert);
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc
index d069220..c93602e1 100644
--- a/components/exo/surface_tree_host.cc
+++ b/components/exo/surface_tree_host.cc
@@ -250,7 +250,7 @@
       host_window()->GetLocalSurfaceIdAllocation().allocation_time();
   root_surface_->AppendSurfaceHierarchyContentsToFrame(
       root_surface_origin_, device_scale_factor,
-      layer_tree_frame_sink_holder_.get(), &frame);
+      layer_tree_frame_sink_holder_->resource_manager(), &frame);
 
   std::vector<GLbyte*> sync_tokens;
   for (auto& resource : frame.resource_list)
diff --git a/components/heap_profiling/heap_profiling_test_shim.cc b/components/heap_profiling/heap_profiling_test_shim.cc
index ca6efeb9..bae0523 100644
--- a/components/heap_profiling/heap_profiling_test_shim.cc
+++ b/components/heap_profiling/heap_profiling_test_shim.cc
@@ -19,8 +19,7 @@
 }
 
 HeapProfilingTestShim::HeapProfilingTestShim(JNIEnv* env, jobject obj) {}
-
-HeapProfilingTestShim::~HeapProfilingTestShim() {}
+HeapProfilingTestShim::~HeapProfilingTestShim() = default;
 
 void HeapProfilingTestShim::Destroy(JNIEnv* env,
                                     const JavaParamRef<jobject>& obj) {
@@ -33,6 +32,7 @@
     const base::android::JavaParamRef<jstring>& mode,
     jboolean dynamically_start_profiling,
     const base::android::JavaParamRef<jstring>& stack_mode,
+    jboolean stream_samples,
     jboolean should_sample,
     jboolean sample_everything) {
   heap_profiling::TestDriver driver;
@@ -42,6 +42,7 @@
   options.stack_mode = heap_profiling::ConvertStringToStackMode(
       base::android::ConvertJavaStringToUTF8(stack_mode));
   options.profiling_already_started = !dynamically_start_profiling;
+  options.stream_samples = stream_samples;
   options.should_sample = should_sample;
   options.sample_everything = sample_everything;
   return driver.RunTest(options);
diff --git a/components/heap_profiling/heap_profiling_test_shim.h b/components/heap_profiling/heap_profiling_test_shim.h
index 134d548..558933c 100644
--- a/components/heap_profiling/heap_profiling_test_shim.h
+++ b/components/heap_profiling/heap_profiling_test_shim.h
@@ -23,6 +23,7 @@
       const base::android::JavaParamRef<jstring>& mode,
       jboolean dynamically_start_profiling,
       const base::android::JavaParamRef<jstring>& stack_mode,
+      jboolean stream_samples,
       jboolean should_sample,
       jboolean sample_everything);
 
diff --git a/components/heap_profiling/javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java b/components/heap_profiling/javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java
index f55ceaf8..c7f788e 100644
--- a/components/heap_profiling/javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java
+++ b/components/heap_profiling/javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java
@@ -23,9 +23,9 @@
      *  rather than native stacks.
      */
     public boolean runTestForMode(String mode, boolean dynamicallyStartProfiling, String stackMode,
-            boolean shouldSample, boolean sampleEverything) {
+            boolean streamSamples, boolean shouldSample, boolean sampleEverything) {
         return nativeRunTestForMode(mNativeHeapProfilingTestShim, mode, dynamicallyStartProfiling,
-                stackMode, shouldSample, sampleEverything);
+                stackMode, streamSamples, shouldSample, sampleEverything);
     }
 
     /**
@@ -43,6 +43,6 @@
     private native long nativeInit();
     private native void nativeDestroy(long nativeHeapProfilingTestShim);
     private native boolean nativeRunTestForMode(long nativeHeapProfilingTestShim, String mode,
-            boolean dynamicallyStartProfiling, String stackMode, boolean shouldSample,
-            boolean sampleEverything);
+            boolean dynamicallyStartProfiling, String stackMode, boolean streamSamples,
+            boolean shouldSample, boolean sampleEverything);
 }
diff --git a/components/heap_profiling/supervisor.cc b/components/heap_profiling/supervisor.cc
index 70afb5f..987902b3 100644
--- a/components/heap_profiling/supervisor.cc
+++ b/components/heap_profiling/supervisor.cc
@@ -60,24 +60,27 @@
 
 void Supervisor::Start(content::ServiceManagerConnection* connection,
                        base::OnceClosure closure) {
+  // TODO(alph): Obtain stream_samples from the command line / Finch.
   Start(connection, GetModeForStartup(), GetStackModeForStartup(),
-        GetSamplingRateForStartup(), std::move(closure));
+        true /* stream_samples */, GetSamplingRateForStartup(),
+        std::move(closure));
 }
 
 void Supervisor::Start(content::ServiceManagerConnection* connection,
                        Mode mode,
                        mojom::StackMode stack_mode,
+                       bool stream_samples,
                        uint32_t sampling_rate,
                        base::OnceClosure closure) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   DCHECK(!started_);
 
   base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})
-      ->PostTask(FROM_HERE,
-                 base::BindOnce(&Supervisor::StartServiceOnIOThread,
-                                base::Unretained(this),
-                                connection->GetConnector()->Clone(), mode,
-                                stack_mode, sampling_rate, std::move(closure)));
+      ->PostTask(FROM_HERE, base::BindOnce(&Supervisor::StartServiceOnIOThread,
+                                           base::Unretained(this),
+                                           connection->GetConnector()->Clone(),
+                                           mode, stack_mode, stream_samples,
+                                           sampling_rate, std::move(closure)));
 }
 
 Mode Supervisor::GetMode() {
@@ -180,12 +183,13 @@
     std::unique_ptr<service_manager::Connector> connector,
     Mode mode,
     mojom::StackMode stack_mode,
+    bool stream_samples,
     uint32_t sampling_rate,
     base::OnceClosure closure) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
 
-  controller_.reset(
-      new Controller(std::move(connector), stack_mode, sampling_rate));
+  controller_.reset(new Controller(std::move(connector), stack_mode,
+                                   stream_samples, sampling_rate));
   base::WeakPtr<Controller> controller_weak_ptr = controller_->GetWeakPtr();
 
   base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI})
diff --git a/components/heap_profiling/supervisor.h b/components/heap_profiling/supervisor.h
index b4b8515..592b72e 100644
--- a/components/heap_profiling/supervisor.h
+++ b/components/heap_profiling/supervisor.h
@@ -72,6 +72,7 @@
   void Start(content::ServiceManagerConnection* connection,
              Mode mode,
              mojom::StackMode stack_mode,
+             bool stream_samples,
              uint32_t sampling_rate,
              base::OnceClosure callback);
 
@@ -116,6 +117,7 @@
       std::unique_ptr<service_manager::Connector> connector,
       Mode mode,
       mojom::StackMode stack_mode,
+      bool stream_samples,
       uint32_t sampling_rate,
       base::OnceClosure callback);
 
diff --git a/components/heap_profiling/test_driver.cc b/components/heap_profiling/test_driver.cc
index 7a6decc..6799497c 100644
--- a/components/heap_profiling/test_driver.cc
+++ b/components/heap_profiling/test_driver.cc
@@ -559,7 +559,7 @@
                           base::WaitableEvent::InitialState::NOT_SIGNALED) {
   partition_allocator_.init();
 }
-TestDriver::~TestDriver() {}
+TestDriver::~TestDriver() = default;
 
 bool TestDriver::RunTest(const Options& options) {
   options_ = options;
@@ -723,8 +723,8 @@
                                ? (options_.sample_everything ? 2 : kSampleRate)
                                : 1;
   Supervisor::GetInstance()->Start(connection, options_.mode,
-                                   options_.stack_mode, sampling_rate,
-                                   std::move(start_callback));
+                                   options_.stack_mode, options_.stream_samples,
+                                   sampling_rate, std::move(start_callback));
 
   return true;
 }
@@ -776,8 +776,8 @@
                                ? (options_.sample_everything ? 2 : kSampleRate)
                                : 1;
   Supervisor::GetInstance()->Start(connection, options_.mode,
-                                   options_.stack_mode, sampling_rate,
-                                   std::move(start_callback));
+                                   options_.stack_mode, options_.stream_samples,
+                                   sampling_rate, std::move(start_callback));
 
   run_loop->Run();
 
diff --git a/components/heap_profiling/test_driver.h b/components/heap_profiling/test_driver.h
index f897c672..03e447b 100644
--- a/components/heap_profiling/test_driver.h
+++ b/components/heap_profiling/test_driver.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/synchronization/waitable_event.h"
+#include "components/services/heap_profiling/public/cpp/settings.h"
 #include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
 
 namespace base {
@@ -19,8 +20,6 @@
 
 namespace heap_profiling {
 
-enum class Mode;
-
 // This class runs tests for the Heap Profiling Service, a cross-platform,
 // multi-process component.
 //
@@ -45,23 +44,28 @@
  public:
   struct Options {
     // The profiling mode to test.
-    Mode mode;
+    Mode mode = Mode::kBrowser;
 
     // The stack profiling mode to test.
-    mojom::StackMode stack_mode;
+    mojom::StackMode stack_mode = mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES;
+
+    // Whether the client should stream samples as they are collected through
+    // the provided pipe. When false the samples are accumulated on the client
+    // side and can be retrieved later.
+    bool stream_samples = true;
 
     // Whether the caller has already started profiling with the given mode.
     // When false, the test driver is responsible for starting profiling.
-    bool profiling_already_started;
+    bool profiling_already_started = false;
 
     // Whether to test sampling.
-    bool should_sample;
+    bool should_sample = true;
 
     // When set to true, the internal sampling_rate is set to 2. While this
     // doesn't record all allocations, it should record all test allocations
     // made in this file with exponentially high probability.
     // When set to false, the internal sampling rate is set to 10000.
-    bool sample_everything;
+    bool sample_everything = false;
   };
 
   TestDriver();
diff --git a/components/mirroring/browser/single_client_video_capture_host.cc b/components/mirroring/browser/single_client_video_capture_host.cc
index d321b37..9c27142 100644
--- a/components/mirroring/browser/single_client_video_capture_host.cc
+++ b/components/mirroring/browser/single_client_video_capture_host.cc
@@ -173,6 +173,12 @@
   std::move(callback).Run(media::VideoCaptureFormats());
 }
 
+void SingleClientVideoCaptureHost::OnLog(int32_t device_id,
+                                         const std::string& message) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Ignore this call.
+}
+
 void SingleClientVideoCaptureHost::OnNewBuffer(
     int buffer_id,
     media::mojom::VideoBufferHandlePtr buffer_handle) {
diff --git a/components/mirroring/browser/single_client_video_capture_host.h b/components/mirroring/browser/single_client_video_capture_host.h
index 1db62159..b44bdc2 100644
--- a/components/mirroring/browser/single_client_video_capture_host.h
+++ b/components/mirroring/browser/single_client_video_capture_host.h
@@ -65,6 +65,7 @@
   void GetDeviceFormatsInUse(int32_t device_id,
                              int32_t session_id,
                              GetDeviceFormatsInUseCallback callback) override;
+  void OnLog(int32_t device_id, const std::string& message) override;
 
   // media::VideoFrameReceiver implementations
   using Buffer = VideoCaptureDevice::Client::Buffer;
diff --git a/components/mirroring/service/fake_video_capture_host.h b/components/mirroring/service/fake_video_capture_host.h
index f74af05..4d71268a 100644
--- a/components/mirroring/service/fake_video_capture_host.h
+++ b/components/mirroring/service/fake_video_capture_host.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_MIRRORING_SERVICE_FAKE_VIDEO_CAPTURE_HOST_H_
 #define COMPONENTS_MIRRORING_SERVICE_FAKE_VIDEO_CAPTURE_HOST_H_
 
+#include <string>
+
 #include "media/capture/mojom/video_capture.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -24,6 +26,7 @@
   MOCK_METHOD3(Resume,
                void(int32_t, int32_t, const media::VideoCaptureParams&));
   MOCK_METHOD0(OnStopped, void());
+  MOCK_METHOD2(OnLog, void(int32_t, const std::string&));
 
   void Start(int32_t device_id,
              int32_t session_id,
diff --git a/components/omnibox/browser/vector_icons/drive_docs.icon b/components/omnibox/browser/vector_icons/drive_docs.icon
index f1ffee5..a2c78b3 100644
--- a/components/omnibox/browser/vector_icons/drive_docs.icon
+++ b/components/omnibox/browser/vector_icons/drive_docs.icon
@@ -2,30 +2,30 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-CANVAS_DIMENSIONS, 18,
+CANVAS_DIMENSIONS, 16,
 PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4,
-MOVE_TO, 16, 0,
+MOVE_TO, 14, 0,
 H_LINE_TO, 2,
 CUBIC_TO, 0.9f, 0, 0, 0.9f, 0, 2,
-R_V_LINE_TO, 14,
+R_V_LINE_TO, 12,
 R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2,
-R_H_LINE_TO, 14,
+R_H_LINE_TO, 12,
 R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
 V_LINE_TO, 2,
 R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
 CLOSE,
-R_MOVE_TO, -1.99f, 6,
-H_LINE_TO, 4,
-V_LINE_TO, 4,
-R_H_LINE_TO, 10.01f,
+MOVE_TO, 3, 3,
+H_LINE_TO, 13,
+V_LINE_TO, 5,
+H_LINE_TO, 3,
 CLOSE,
-R_MOVE_TO, 0, 4,
-H_LINE_TO, 4,
-V_LINE_TO, 8,
-R_H_LINE_TO, 10.01f,
+MOVE_TO, 3, 7,
+H_LINE_TO, 13,
+V_LINE_TO, 9,
+H_LINE_TO, 3,
 CLOSE,
-R_MOVE_TO, -3, 4,
-H_LINE_TO, 4,
-R_V_LINE_TO, -2,
-R_H_LINE_TO, 7.01f,
+MOVE_TO, 3, 11,
+H_LINE_TO, 9,
+V_LINE_TO, 13,
+H_LINE_TO, 3,
 CLOSE
\ No newline at end of file
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc
index 7881aa2..62dfb77 100644
--- a/components/password_manager/core/browser/new_password_form_manager.cc
+++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -501,6 +501,7 @@
   result->password_overridden_ = password_overridden_;
   result->retry_password_form_password_update_ =
       retry_password_form_password_update_;
+  result->likely_form_filling_ = likely_form_filling_;
   result->is_submitted_ = is_submitted_;
 
   return result;
diff --git a/components/password_manager/core/browser/new_password_form_manager.h b/components/password_manager/core/browser/new_password_form_manager.h
index 248192e..a0a71c6 100644
--- a/components/password_manager/core/browser/new_password_form_manager.h
+++ b/components/password_manager/core/browser/new_password_form_manager.h
@@ -152,6 +152,14 @@
   }
 
   FormSaver* form_saver() { return form_saver_.get(); }
+
+  const VotesUploader& votes_uploader() const { return votes_uploader_; }
+
+  LikelyFormFilling likely_form_filling() const { return likely_form_filling_; }
+
+  void set_likely_form_filling(LikelyFormFilling likely_form_filling) {
+    likely_form_filling_ = likely_form_filling;
+  }
 #endif
 
   // TODO(https://crbug.com/831123): Remove it when the old form parsing is
diff --git a/components/password_manager/core/browser/new_password_form_manager_unittest.cc b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
index dd0e2146..c794b9d 100644
--- a/components/password_manager/core/browser/new_password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
@@ -1143,11 +1143,15 @@
 TEST_F(NewPasswordFormManagerTest, Clone) {
   TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
   fetcher_->SetNonFederated({}, 0u);
-
   // Provisionally save in order to create pending credentials.
   ASSERT_TRUE(
       form_manager_->ProvisionallySaveIfIsManaged(submitted_form_, &driver_));
 
+  // Make sure likely_form_filling is not in the default state anymore.
+  EXPECT_EQ(LikelyFormFilling::kNoFilling,
+            form_manager_->likely_form_filling());
+  form_manager_->set_likely_form_filling(LikelyFormFilling::kFillOnPageLoad);
+
   std::unique_ptr<NewPasswordFormManager> cloned_manager =
       form_manager_->Clone();
 
@@ -1159,12 +1163,15 @@
   EXPECT_EQ(form_manager_->metrics_recorder(),
             cloned_manager->metrics_recorder());
 
+  EXPECT_EQ(form_manager_->votes_uploader(), cloned_manager->votes_uploader());
   EXPECT_EQ(form_manager_->GetPendingCredentials(),
             cloned_manager->GetPendingCredentials());
   ASSERT_TRUE(cloned_manager->GetSubmittedForm());
   EXPECT_EQ(*form_manager_->GetSubmittedForm(),
             *cloned_manager->GetSubmittedForm());
   EXPECT_TRUE(cloned_manager->is_submitted());
+  EXPECT_EQ(form_manager_->likely_form_filling(),
+            cloned_manager->likely_form_filling());
 }
 
 // Extracts the information whether parsing was successful from a metric
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 4a8b29e..096889c 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -1036,6 +1036,7 @@
   result->is_possible_change_password_form_without_username_ =
       is_possible_change_password_form_without_username_;
   result->votes_uploader_ = votes_uploader_;
+  result->likely_form_filling_ = likely_form_filling_;
 
   return result;
 }
diff --git a/components/password_manager/core/browser/password_form_manager.h b/components/password_manager/core/browser/password_form_manager.h
index a1f422a..824f965 100644
--- a/components/password_manager/core/browser/password_form_manager.h
+++ b/components/password_manager/core/browser/password_form_manager.h
@@ -224,6 +224,8 @@
       size_t filtered_count) override;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(PasswordFormManagerTest, Clone_DataIsCopied);
+
   // Through |driver|, supply the associated frame with appropriate information
   // (fill data, whether to allow password generation, etc.).
   void ProcessFrameInternal(const base::WeakPtr<PasswordManagerDriver>& driver);
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc
index 67f7741..731c70db 100644
--- a/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -4117,6 +4117,41 @@
   EXPECT_EQ(pending, passed);
 }
 
+// Check that a cloned PasswordFormManager correctly copies the data.
+TEST_F(PasswordFormManagerTest, Clone_DataIsCopied) {
+  // Construct some non-default data.
+  fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
+  form_manager()->ProvisionallySave(*observed_form());
+
+  EXPECT_NE(autofill::PasswordForm(), form_manager()->pending_credentials_);
+  auto flip_bool = [](bool& b) { b = !b; };
+  flip_bool(form_manager()->is_new_login_);
+  flip_bool(form_manager()->has_generated_password_);
+  form_manager()->generated_password_.push_back('c');
+  flip_bool(form_manager()->password_overridden_);
+  flip_bool(form_manager()->retry_password_form_password_update_);
+  flip_bool(form_manager()->is_possible_change_password_form_without_username_);
+  form_manager()->votes_uploader_.set_is_manual_generation(
+      !form_manager()->votes_uploader_.is_manual_generation());
+  EXPECT_NE(LikelyFormFilling::kNoFilling,
+            form_manager()->likely_form_filling_);
+
+  // Clone the manager and make sure the copied data matches.
+  std::unique_ptr<const PasswordFormManager> clone = form_manager()->Clone();
+  EXPECT_EQ(form_manager()->pending_credentials_, clone->pending_credentials_);
+  EXPECT_EQ(form_manager()->is_new_login_, clone->is_new_login_);
+  EXPECT_EQ(form_manager()->has_generated_password_,
+            clone->has_generated_password_);
+  EXPECT_EQ(form_manager()->generated_password_, clone->generated_password_);
+  EXPECT_EQ(form_manager()->password_overridden_, clone->password_overridden_);
+  EXPECT_EQ(form_manager()->retry_password_form_password_update_,
+            clone->retry_password_form_password_update_);
+  EXPECT_EQ(form_manager()->is_possible_change_password_form_without_username_,
+            clone->is_possible_change_password_form_without_username_);
+  EXPECT_EQ(form_manager()->votes_uploader_, clone->votes_uploader_);
+  EXPECT_EQ(form_manager()->likely_form_filling_, clone->likely_form_filling_);
+}
+
 // Verifies that URL keyed metrics are recorded for the filling of passwords
 // into forms and HTTP Basic auth.
 TEST_F(PasswordFormManagerTest, TestUkmForFilling) {
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index f7aa982..dd8eaf3 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -555,6 +555,7 @@
 
   form_managers_.clear();
   predictions_.clear();
+  store_password_called_ = false;
 }
 
 void PasswordManager::UpdateFormManagers() {
@@ -914,7 +915,7 @@
   if (client_ && client_->GetMetricsRecorder())
     client_->GetMetricsRecorder()->RecordFormManagerAvailable(availability);
 
-  if (!matching_form_manager) {
+  if (!matching_form_manager && !store_password_called_) {
     RecordProvisionalSaveFailure(
         PasswordManagerMetricsRecorder::NO_MATCHING_FORM, submitted_form.origin,
         logger.get());
@@ -951,6 +952,11 @@
   matching_manager->GetMetricsRecorder()->RecordFirstFillingResult(result);
 }
 
+void PasswordManager::NotifyStorePasswordCalled() {
+  store_password_called_ = true;
+  DropFormManagers();
+}
+
 void PasswordManager::ProvisionallySaveManager(
     const PasswordForm& form,
     PasswordFormManager* matched_manager,
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index 7129d048..99a30fd 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -188,6 +188,9 @@
                              uint32_t form_renderer_id,
                              int32_t result);
 
+  // Notifies that Credential Management API function store() is called.
+  void NotifyStorePasswordCalled();
+
  private:
   FRIEND_TEST_ALL_PREFIXES(
       PasswordManagerTest,
@@ -259,7 +262,6 @@
   // gone.
   PasswordFormManagerInterface* GetSubmittedManager() const;
 
- private:
   // Returns the form manager that corresponds to the submitted form. It also
   // sets |submitted_form_manager_| to nullptr.
   // TODO(https://crbug.com/831123): Remove when the old PasswordFormManager is
@@ -358,6 +360,11 @@
   // If true, it turns off using PasswordFormManager in PasswordManager.
   const bool is_only_new_parser_enabled_;
 
+  // True if Credential Management API function store() was called. In this case
+  // PasswordManager does not need to show a save/update prompt since
+  // CredentialManagerImpl takes care of it.
+  bool store_password_called_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(PasswordManager);
 };
 
diff --git a/components/password_manager/core/browser/password_manager_client_helper.cc b/components/password_manager/core/browser/password_manager_client_helper.cc
index ac022b2..fe9715a 100644
--- a/components/password_manager/core/browser/password_manager_client_helper.cc
+++ b/components/password_manager/core/browser/password_manager_client_helper.cc
@@ -59,7 +59,7 @@
 void PasswordManagerClientHelper::NotifyStorePasswordCalled() {
   // If a site stores a credential the autofill password manager shouldn't kick
   // in.
-  delegate_->GetPasswordManager()->DropFormManagers();
+  delegate_->GetPasswordManager()->NotifyStorePasswordCalled();
 }
 
 void PasswordManagerClientHelper::NotifyUserAutoSignin() {
diff --git a/components/password_manager/core/browser/password_manager_client_helper.h b/components/password_manager/core/browser/password_manager_client_helper.h
index dac3fbf..34c69160 100644
--- a/components/password_manager/core/browser/password_manager_client_helper.h
+++ b/components/password_manager/core/browser/password_manager_client_helper.h
@@ -54,7 +54,7 @@
 
   // Common logic for IOSChromePasswordManagerClient and
   // ChromePasswordManagerClient implementation of NotifyStorePasswordCalled.
-  // Calls DropFormManagers on PasswordManager corresponding to the client.
+  // Notifies PasswordManager corresponding to the client.
   void NotifyStorePasswordCalled();
 
   // Common logic for IOSChromePasswordManagerClient and
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index d04a263b..584ca4c 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -3333,4 +3333,35 @@
               FormMatches(submitted_form));
 }
 
+// Tests that no save prompt from form manager is shown when Credentials
+// Management API function store is called.
+TEST_F(PasswordManagerTest, NoSavePromptAfterStoreCalled) {
+  for (bool new_parsing_for_saving : {false, true}) {
+    SCOPED_TRACE(testing::Message()
+                 << "new_parsing_for_saving = " << new_parsing_for_saving);
+    base::test::ScopedFeatureList scoped_feature_list;
+    if (new_parsing_for_saving)
+      TurnOnNewParsingForSaving(&scoped_feature_list);
+
+    EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
+        .WillRepeatedly(Return(true));
+
+    PasswordForm form(MakeSimpleForm());
+    EXPECT_CALL(*store_, GetLogins(_, _))
+        .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+
+    manager()->OnPasswordFormsParsed(&driver_, {form});
+
+    // Simulate that navigator.credentials.store function is called.
+    manager()->NotifyStorePasswordCalled();
+
+    OnPasswordFormSubmitted(form);
+    EXPECT_FALSE(manager()->GetSubmittedManagerForTest());
+    EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
+
+    manager()->OnPasswordFormsRendered(&driver_, {}, true);
+    testing::Mock::VerifyAndClearExpectations(&client_);
+  }
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/votes_uploader.cc b/components/password_manager/core/browser/votes_uploader.cc
index b52b9cd..d29b32f1 100644
--- a/components/password_manager/core/browser/votes_uploader.cc
+++ b/components/password_manager/core/browser/votes_uploader.cc
@@ -6,6 +6,7 @@
 
 #include <ctype.h>
 #include <map>
+#include <tuple>
 
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
@@ -531,4 +532,22 @@
   form_structure->set_password_length_vote(randomized_length);
 }
 
+bool VotesUploader::operator==(const VotesUploader& other) const {
+  return std::tie(client_, generation_popup_was_shown_, is_manual_generation_,
+                  generation_element_, has_username_edited_vote_,
+                  has_username_correction_vote_, username_correction_vote_,
+                  has_passwords_revealed_vote_, password_overridden_,
+                  is_possible_change_password_form_, has_generated_password_,
+                  generated_password_changed_) ==
+         std::tie(
+             other.client_, other.generation_popup_was_shown_,
+             other.is_manual_generation_, other.generation_element_,
+             other.has_username_edited_vote_,
+             other.has_username_correction_vote_,
+             other.username_correction_vote_,
+             other.has_passwords_revealed_vote_, other.password_overridden_,
+             other.is_possible_change_password_form_,
+             other.has_generated_password_, other.generated_password_changed_);
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/votes_uploader.h b/components/password_manager/core/browser/votes_uploader.h
index a8318d1..89fb7b4 100644
--- a/components/password_manager/core/browser/votes_uploader.h
+++ b/components/password_manager/core/browser/votes_uploader.h
@@ -84,6 +84,8 @@
   void GeneratePasswordAttributesVote(const base::string16& password_value,
                                       autofill::FormStructure* form_structure);
 
+  bool operator==(const VotesUploader& other) const;
+
   bool get_generation_popup_was_shown() const {
     return generation_popup_was_shown_;
   }
diff --git a/components/search_engines/default_search_manager.cc b/components/search_engines/default_search_manager.cc
index 07f30687e..ffe8ec2 100644
--- a/components/search_engines/default_search_manager.cc
+++ b/components/search_engines/default_search_manager.cc
@@ -109,8 +109,9 @@
 void DefaultSearchManager::AddPrefValueToMap(
     std::unique_ptr<base::DictionaryValue> value,
     PrefValueMap* pref_value_map) {
+  DCHECK(value);
   pref_value_map->SetValue(kDefaultSearchProviderDataPrefName,
-                           std::move(value));
+                           base::Value::FromUniquePtrValue(std::move(value)));
 }
 
 // static
diff --git a/components/search_engines/default_search_policy_handler.cc b/components/search_engines/default_search_policy_handler.cc
index 68863cc..9ff8e9e 100644
--- a/components/search_engines/default_search_policy_handler.cc
+++ b/components/search_engines/default_search_policy_handler.cc
@@ -278,7 +278,7 @@
   base::Value* value;
   base::ListValue* list_value;
   if (!prefs->GetValue(path, &value) || !value->GetAsList(&list_value))
-    prefs->SetValue(path, std::make_unique<base::ListValue>());
+    prefs->SetValue(path, base::Value(base::Value::Type::LIST));
 }
 
 }  // namespace policy
diff --git a/components/services/heap_profiling/connection_manager.cc b/components/services/heap_profiling/connection_manager.cc
index 2a115e1..2b8f8fd 100644
--- a/components/services/heap_profiling/connection_manager.cc
+++ b/components/services/heap_profiling/connection_manager.cc
@@ -5,6 +5,7 @@
 #include "components/services/heap_profiling/connection_manager.h"
 
 #include "base/bind.h"
+#include "base/json/string_escape.h"
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_current.h"
 #include "base/metrics/histogram_macros.h"
@@ -74,13 +75,15 @@
              scoped_refptr<ReceiverPipe> p,
              mojom::ProcessType process_type,
              uint32_t sampling_rate,
-             mojom::StackMode stack_mode)
+             mojom::StackMode stack_mode,
+             bool stream_samples)
       : thread(base::StringPrintf("Sender %lld thread",
                                   static_cast<long long>(pid))),
         client(std::move(client)),
         pipe(p),
         process_type(process_type),
         stack_mode(stack_mode),
+        stream_samples(stream_samples),
         tracker(std::move(complete_cb), backtrace_storage),
         sampling_rate(sampling_rate) {}
 
@@ -103,6 +106,7 @@
   scoped_refptr<StreamParser> parser;
   mojom::ProcessType process_type;
   mojom::StackMode stack_mode;
+  bool stream_samples;
 
   // Danger: This lives on the |thread| member above. The connection manager
   // lives on the I/O thread, so accesses to the variable must be synchronized.
@@ -159,7 +163,8 @@
 
   auto connection = std::make_unique<Connection>(
       std::move(complete_cb), &backtrace_storage_, pid, std::move(client),
-      new_pipe, process_type, params->sampling_rate, params->stack_mode);
+      new_pipe, process_type, params->sampling_rate, params->stack_mode,
+      params->stream_samples);
 
   base::Thread::Options options;
   options.message_loop_type = base::MessageLoop::TYPE_IO;
@@ -254,6 +259,13 @@
   for (auto& it : connections_) {
     base::ProcessId pid = it.first;
     Connection* connection = it.second.get();
+    if (!connection->stream_samples) {
+      connection->client->RetrieveHeapProfile(base::BindOnce(
+          &ConnectionManager::HeapProfileRetrieved, weak_factory_.GetWeakPtr(),
+          tracking, pid, connection->process_type, keep_small_allocations,
+          strip_path_from_mapped_files, connection->sampling_rate));
+      continue;
+    }
     int barrier_id = next_barrier_id_++;
 
     // Register for callback before requesting the dump so we don't race for the
@@ -270,6 +282,65 @@
   }
 }
 
+void ConnectionManager::HeapProfileRetrieved(
+    scoped_refptr<DumpProcessesForTracingTracking> tracking,
+    base::ProcessId pid,
+    mojom::ProcessType process_type,
+    bool keep_small_allocations,
+    bool strip_path_from_mapped_files,
+    uint32_t sampling_rate,
+    mojom::HeapProfilePtr profile) {
+  AllocationCountMap counts;
+  AllocationTracker::ContextMap context_map;
+  AllocationTracker::AddressToStringMap string_map;
+  BacktraceStorage backtrace_storage;
+  BacktraceStorage::Lock backtrace_storage_lock(&backtrace_storage);
+
+  bool success = true;
+  for (const mojom::HeapProfileSamplePtr& sample : profile->samples) {
+    int context_id = 0;
+    if (sample->context_id) {
+      auto it = profile->strings.find(sample->context_id);
+      if (it == profile->strings.end()) {
+        success = false;
+        break;
+      }
+      const std::string& context = it->second;
+      // Escape the strings early, to simplify exporting a heap dump.
+      std::string escaped_context;
+      base::EscapeJSONString(context, false /* put_in_quotes */,
+                             &escaped_context);
+      context_id = context_map
+                       .emplace(std::move(escaped_context),
+                                static_cast<int>(context_map.size() + 1))
+                       .first->second;
+    }
+    const Backtrace* backtrace = backtrace_storage.Insert(
+        std::vector<Address>(sample->stack.begin(), sample->stack.end()));
+    AllocatorType allocator = static_cast<AllocatorType>(sample->allocator);
+    if (allocator >= AllocatorType::kCount) {
+      success = false;
+      break;
+    }
+    AllocationEvent alloc(allocator, Address(0), sample->size, backtrace,
+                          context_id);
+    ++counts[alloc];
+  }
+
+  for (const auto& str : profile->strings) {
+    std::string quoted_string;
+    // Escape the strings before saving them, to simplify exporting a heap dump.
+    base::EscapeJSONString(str.second, false /* put_in_quotes */,
+                           &quoted_string);
+    string_map.emplace(str.first, std::move(quoted_string));
+  }
+
+  DoDumpOneProcessForTracing(
+      tracking, pid, process_type, keep_small_allocations,
+      strip_path_from_mapped_files, sampling_rate, success, std::move(counts),
+      std::move(context_map), std::move(string_map));
+}
+
 void ConnectionManager::DoDumpOneProcessForTracing(
     scoped_refptr<DumpProcessesForTracingTracking> tracking,
     base::ProcessId pid,
diff --git a/components/services/heap_profiling/connection_manager.h b/components/services/heap_profiling/connection_manager.h
index 6c746b3..6571f9f 100644
--- a/components/services/heap_profiling/connection_manager.h
+++ b/components/services/heap_profiling/connection_manager.h
@@ -88,6 +88,15 @@
   struct Connection;
   struct DumpProcessesForTracingTracking;
 
+  void HeapProfileRetrieved(
+      scoped_refptr<DumpProcessesForTracingTracking> tracking,
+      base::ProcessId pid,
+      mojom::ProcessType process_type,
+      bool keep_small_allocations,
+      bool strip_path_from_mapped_files,
+      uint32_t sampling_rate,
+      mojom::HeapProfilePtr profile);
+
   void DoDumpOneProcessForTracing(
       scoped_refptr<DumpProcessesForTracingTracking> tracking,
       base::ProcessId pid,
diff --git a/components/services/heap_profiling/public/cpp/client.cc b/components/services/heap_profiling/public/cpp/client.cc
index 020ef5e..39cd6c1d 100644
--- a/components/services/heap_profiling/public/cpp/client.cc
+++ b/components/services/heap_profiling/public/cpp/client.cc
@@ -128,6 +128,10 @@
   SamplingProfilerWrapper::FlushPipe(barrier_id);
 }
 
+void Client::RetrieveHeapProfile(RetrieveHeapProfileCallback callback) {
+  std::move(callback).Run(sampling_profiler_->RetrieveHeapProfile());
+}
+
 void Client::StartProfilingInternal(mojom::ProfilingParamsPtr params) {
   sampling_profiler_->StartProfiling(sender_pipe_.get(), std::move(params));
 }
diff --git a/components/services/heap_profiling/public/cpp/client.h b/components/services/heap_profiling/public/cpp/client.h
index e06103c7..23abac2 100644
--- a/components/services/heap_profiling/public/cpp/client.h
+++ b/components/services/heap_profiling/public/cpp/client.h
@@ -27,6 +27,7 @@
   // mojom::ProfilingClient overrides:
   void StartProfiling(mojom::ProfilingParamsPtr params) override;
   void FlushMemlogPipe(uint32_t barrier_id) override;
+  void RetrieveHeapProfile(RetrieveHeapProfileCallback callback) override;
 
   void BindToInterface(mojom::ProfilingClientRequest request);
 
diff --git a/components/services/heap_profiling/public/cpp/controller.cc b/components/services/heap_profiling/public/cpp/controller.cc
index afb48330..8ab69c5 100644
--- a/components/services/heap_profiling/public/cpp/controller.cc
+++ b/components/services/heap_profiling/public/cpp/controller.cc
@@ -16,10 +16,12 @@
 
 Controller::Controller(std::unique_ptr<service_manager::Connector> connector,
                        mojom::StackMode stack_mode,
+                       bool stream_samples,
                        uint32_t sampling_rate)
     : connector_(std::move(connector)),
       sampling_rate_(sampling_rate),
       stack_mode_(stack_mode),
+      stream_samples_(stream_samples),
       weak_factory_(this) {
   DCHECK_NE(sampling_rate, 0u);
 
@@ -50,6 +52,7 @@
 
   mojom::ProfilingParamsPtr params = mojom::ProfilingParams::New();
   params->sampling_rate = sampling_rate_;
+  params->stream_samples = stream_samples_;
   params->sender_pipe = mojo::WrapPlatformHandle(pipes.PassSender());
   params->stack_mode = stack_mode_;
   heap_profiling_service_->AddProfilingClient(
diff --git a/components/services/heap_profiling/public/cpp/controller.h b/components/services/heap_profiling/public/cpp/controller.h
index ab077b0d..969f89e 100644
--- a/components/services/heap_profiling/public/cpp/controller.h
+++ b/components/services/heap_profiling/public/cpp/controller.h
@@ -42,6 +42,7 @@
   // named |sampling_interval|.
   Controller(std::unique_ptr<service_manager::Connector> connector,
              mojom::StackMode stack_mode,
+             bool stream_samples,
              uint32_t sampling_rate);
   ~Controller();
 
@@ -71,6 +72,7 @@
   // The same sampling rate and stack mode is used for each client.
   const uint32_t sampling_rate_ = 1;
   const mojom::StackMode stack_mode_;
+  const bool stream_samples_;
 
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<Controller> weak_factory_;
diff --git a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc
index b97ec3c5..25fbc910 100644
--- a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc
+++ b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc
@@ -4,6 +4,8 @@
 
 #include "components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h"
 
+#include <utility>
+
 #include "base/allocator/buildflags.h"
 #include "base/atomicops.h"
 #include "base/bind.h"
@@ -424,8 +426,12 @@
     *context = allocation_context.type_name;
 }
 
-void SerializeFramesFromBacktrace(FrameSerializer* serializer,
-                                  const char** context) {
+// Captures up to |max_entries| stack frames using the buffer pointed by
+// |frames|. Puts the number of captured frames into the |count| output
+// parameters. Returns the pointer to the topmost frame.
+const void** CaptureStackTrace(const void** frames,
+                               size_t max_entries,
+                               size_t* count) {
   // Skip 3 top frames related to the profiler itself, e.g.:
   //   base::debug::StackTrace::StackTrace
   //   heap_profiling::RecordAndSendAlloc
@@ -433,26 +439,33 @@
   size_t skip_frames = 3;
 #if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
     defined(OFFICIAL_BUILD)
-  const void* frames[kMaxStackEntries - 1];
   size_t frame_count =
       base::trace_event::CFIBacktraceAndroid::GetInitializedInstance()->Unwind(
-          frames, kMaxStackEntries - 1);
+          frames, max_entries);
 #elif BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
-  const void* frames[kMaxStackEntries - 1];
-  size_t frame_count = base::debug::TraceStackFramePointers(
-      frames, kMaxStackEntries - 1, skip_frames);
+  size_t frame_count =
+      base::debug::TraceStackFramePointers(frames, max_entries, skip_frames);
   skip_frames = 0;
 #else
-  // Fall-back to capturing the stack with base::debug::StackTrace,
+  // Fall-back to capturing the stack with base::debug::CollectStackTrace,
   // which is likely slower, but more reliable.
-  base::debug::StackTrace stack_trace(kMaxStackEntries - 1);
-  size_t frame_count = 0u;
-  const void* const* frames = stack_trace.Addresses(&frame_count);
+  // TODO(alph): Make CollectStackTrace accept const void** pointer.
+  size_t frame_count =
+      base::debug::CollectStackTrace(const_cast<void**>(frames), max_entries);
 #endif
 
   skip_frames = std::min(skip_frames, frame_count);
-  serializer->AddAllInstructionPointers(frame_count - skip_frames,
-                                        frames + skip_frames);
+  *count = frame_count - skip_frames;
+  return frames + skip_frames;
+}
+
+void SerializeFramesFromBacktrace(FrameSerializer* serializer,
+                                  const char** context) {
+  const void* frames[kMaxStackEntries];
+  size_t frames_count;
+  const void** first_frame =
+      CaptureStackTrace(frames, kMaxStackEntries - 1, &frames_count);
+  serializer->AddAllInstructionPointers(frames_count, first_frame);
 
   // Both thread name and task context require access to TLS.
   if (ScopedAllowAlloc::HasTLSBeenDestroyed())
@@ -605,9 +618,14 @@
   base::PoissonAllocationSampler::Get()->RemoveSamplesObserver(this);
 }
 
+SamplingProfilerWrapper::Sample::Sample() = default;
+SamplingProfilerWrapper::Sample::Sample(Sample&&) = default;
+SamplingProfilerWrapper::Sample::~Sample() = default;
+
 void SamplingProfilerWrapper::StartProfiling(SenderPipe* sender_pipe,
                                              mojom::ProfilingParamsPtr params) {
   size_t sampling_rate = params->sampling_rate;
+  stream_samples_ = params->stream_samples;
   InitAllocationRecorder(sender_pipe, std::move(params));
   auto* sampler = base::PoissonAllocationSampler::Get();
   sampler->SetSamplingInterval(sampling_rate);
@@ -619,17 +637,128 @@
   base::PoissonAllocationSampler::Get()->Stop();
 }
 
+mojom::HeapProfilePtr SamplingProfilerWrapper::RetrieveHeapProfile() {
+  base::PoissonAllocationSampler::ScopedMuteThreadSamples no_samples_scope;
+  base::AutoLock lock(mutex_);
+  mojom::HeapProfilePtr profile = mojom::HeapProfile::New();
+  profile->samples.reserve(samples_.size());
+  for (const auto& pair : samples_) {
+    auto mojo_sample = mojom::HeapProfileSample::New();
+    mojo_sample->allocator = static_cast<uint32_t>(pair.second.allocator);
+    mojo_sample->size = pair.second.size;
+    mojo_sample->context_id = reinterpret_cast<uintptr_t>(pair.second.context);
+    mojo_sample->stack = pair.second.stack;
+    profile->samples.push_back(std::move(mojo_sample));
+  }
+  profile->strings.reserve(strings_.size());
+  for (const char* string : strings_)
+    profile->strings.emplace(reinterpret_cast<uintptr_t>(string), string);
+  return profile;
+}
+
+// The PoissonAllocationSampler that invokes this method guarantees
+// non-reentrancy, i.e. no allocations made within the scope of SampleAdded
+// will produce a sample.
 void SamplingProfilerWrapper::SampleAdded(
     void* address,
     size_t size,
     size_t total,
     base::PoissonAllocationSampler::AllocatorType type,
     const char* context) {
-  RecordAndSendAlloc(ConvertType(type), address, size, context);
+  DCHECK(base::PoissonAllocationSampler::ScopedMuteThreadSamples::IsMuted());
+  if (stream_samples_) {
+    RecordAndSendAlloc(ConvertType(type), address, size, context);
+    return;
+  }
+  base::AutoLock lock(mutex_);
+  Sample sample;
+  sample.allocator = ConvertType(type);
+  sample.size = size;
+  CaptureMode capture_mode = AllocationContextTracker::capture_mode();
+  if (capture_mode == CaptureMode::PSEUDO_STACK ||
+      capture_mode == CaptureMode::MIXED_STACK) {
+    CaptureMixedStack(context, &sample);
+  } else {
+    CaptureNativeStack(context, &sample);
+  }
+  samples_.emplace(address, std::move(sample));
+}
+
+void SamplingProfilerWrapper::CaptureMixedStack(const char* context,
+                                                Sample* sample) {
+  // Allocation context is tracked in TLS. Return nothing if TLS was destroyed.
+  if (ScopedAllowAlloc::HasTLSBeenDestroyed())
+    return;
+  auto* tracker = AllocationContextTracker::GetInstanceForCurrentThread();
+  if (!tracker)
+    return;
+
+  AllocationContext allocation_context;
+  if (!tracker->GetContextSnapshot(&allocation_context))
+    return;
+
+  const base::trace_event::Backtrace& backtrace = allocation_context.backtrace;
+  CHECK_LE(backtrace.frame_count, kMaxStackEntries);
+  std::vector<uint64_t> stack;
+  stack.reserve(backtrace.frame_count);
+  for (int i = base::checked_cast<int>(backtrace.frame_count) - 1; i >= 0;
+       --i) {
+    const base::trace_event::StackFrame& frame = backtrace.frames[i];
+    if (frame.type != base::trace_event::StackFrame::Type::PROGRAM_COUNTER) {
+      const char* name = static_cast<const char*>(frame.value);
+      if (strings_.find(name) == strings_.end())
+        strings_.emplace(name);
+    }
+    stack.push_back(reinterpret_cast<uintptr_t>(frame.value));
+  }
+  sample->stack = std::move(stack);
+  if (!context)
+    context = allocation_context.type_name;
+  sample->context = RecordString(context);
+}
+
+void SamplingProfilerWrapper::CaptureNativeStack(const char* context,
+                                                 Sample* sample) {
+  const void* stack[kMaxStackEntries];
+  size_t frame_count;
+  // One frame is reserved for the thread name.
+  const void** first_frame =
+      CaptureStackTrace(stack, kMaxStackEntries - 1, &frame_count);
+  DCHECK_LT(frame_count, kMaxStackEntries);
+  sample->stack.reserve(frame_count + (g_include_thread_names ? 1 : 0));
+  sample->stack.insert(sample->stack.end(),
+                       reinterpret_cast<uint64_t*>(first_frame),
+                       reinterpret_cast<uint64_t*>(first_frame + frame_count));
+
+  // Both thread name and task context require access to TLS.
+  if (ScopedAllowAlloc::HasTLSBeenDestroyed())
+    return;
+
+  if (g_include_thread_names) {
+    sample->stack.push_back(
+        reinterpret_cast<uintptr_t>(RecordString(GetOrSetThreadName())));
+  }
+  if (!context) {
+    const auto* tracker =
+        AllocationContextTracker::GetInstanceForCurrentThread();
+    if (tracker)
+      context = tracker->TaskContext();
+  }
+  sample->context = RecordString(context);
+}
+
+const char* SamplingProfilerWrapper::RecordString(const char* string) {
+  return string ? *strings_.insert(string).first : nullptr;
 }
 
 void SamplingProfilerWrapper::SampleRemoved(void* address) {
-  RecordAndSendFree(address);
+  DCHECK(base::PoissonAllocationSampler::ScopedMuteThreadSamples::IsMuted());
+  if (stream_samples_) {
+    RecordAndSendFree(address);
+    return;
+  }
+  base::AutoLock lock(mutex_);
+  samples_.erase(address);
 }
 
 }  // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h
index bee5c72..19d5a29c 100644
--- a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h
+++ b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.h
@@ -5,6 +5,10 @@
 #ifndef COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SAMPLING_PROFILER_WRAPPER_H_
 #define COMPONENTS_SERVICES_HEAP_PROFILING_PUBLIC_CPP_SAMPLING_PROFILER_WRAPPER_H_
 
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
 #include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
 #include "components/services/heap_profiling/public/cpp/sender_pipe.h"
 #include "components/services/heap_profiling/public/cpp/stream.h"
@@ -44,7 +48,24 @@
   // logging process so it knows when this operation is complete.
   static void FlushPipe(uint32_t barrier_id);
 
+  mojom::HeapProfilePtr RetrieveHeapProfile();
+
  private:
+  struct Sample {
+    Sample();
+    Sample(Sample&& sample);
+    ~Sample();
+
+    Sample& operator=(Sample&&) = default;
+
+    AllocatorType allocator;
+    size_t size;
+    const char* context = nullptr;
+    std::vector<uint64_t> stack;
+
+    DISALLOW_COPY_AND_ASSIGN(Sample);
+  };
+
   // base::PoissonAllocationSampler::SamplesObserver
   void SampleAdded(void* address,
                    size_t size,
@@ -52,6 +73,26 @@
                    base::PoissonAllocationSampler::AllocatorType,
                    const char* context) override;
   void SampleRemoved(void* address) override;
+
+  void CaptureMixedStack(const char* context, Sample* sample);
+  void CaptureNativeStack(const char* context, Sample* sample);
+  const char* RecordString(const char* string);
+
+  bool stream_samples_ = false;
+
+  // Mutex to access |samples_| and |strings_|.
+  base::Lock mutex_;
+
+  // Samples of the currently live allocations.
+  std::unordered_map<void*, Sample> samples_;
+
+  // When CaptureMode::PSEUDO_STACK or CaptureMode::MIXED_STACK is enabled
+  // the call stack contents of samples may contain strings besides
+  // PC addresses.
+  // In this case each string pointer is also added to the |strings_| set.
+  // The set does only contain pointers to static strings that are never
+  // deleted.
+  std::unordered_set<const char*> strings_;
 };
 
 }  // namespace heap_profiling
diff --git a/components/services/heap_profiling/public/mojom/heap_profiling_client.mojom b/components/services/heap_profiling/public/mojom/heap_profiling_client.mojom
index 8b98d691..6a9607776 100644
--- a/components/services/heap_profiling/public/mojom/heap_profiling_client.mojom
+++ b/components/services/heap_profiling/public/mojom/heap_profiling_client.mojom
@@ -23,6 +23,12 @@
 // A wrapper for parameters that affect each client's implementation of
 // profiling.
 struct ProfilingParams {
+  // When |stream_samples| is true the samples are streamed through the
+  // provided |sender_pipe|. Otherwise, the samples are stored on
+  // the client side during recording and can be retrieved using
+  // |ProfilingClient.RetrieveHeapProfile| method.
+  bool stream_samples;
+
   // The client should record allocations into |memlog_sender_pipe|.
   handle sender_pipe;
 
@@ -37,17 +43,48 @@
   uint32 sampling_rate;
 };
 
+// A single memory allocation sample.
+struct HeapProfileSample {
+  // Allocator type.
+  uint32 allocator;
+
+  // The size in bytes accounted for the sample.
+  uint64 size;
+
+  // Id of the context string.
+  uint64 context_id;
+
+  // Program stack in top to bottom order recorded for the allocation.
+  // Each element of the |stack| is either a PC memory address or a string
+  // if it is among the |strings| map items of |HeapProfile|.
+  array<uint64> stack;
+};
+
+// Heap profile data. Can be retrieved from the client with
+// |RetrieveHeapProfile| method.
+struct HeapProfile {
+  // Samples recorded for the profile.
+  array<HeapProfileSample> samples;
+
+  // Strings used within the profile.
+  map<uint64, string> strings;
+};
+
 // This interface is implemented by "memlog clients" (profiled processes that
 // can send memory allocation events to the profiling process). These functions
 // are called by the profiling process to control the senders.
 interface ProfilingClient {
-  // Start recording allocations and sending them to the profiling process via
-  // |params.sender_pipe|. There is currently no mechanism to stop recording
-  // allocations.
+  // Start recording allocations.
+  // Collected allocations are either streamed to the profiling process via
+  // |params.sender_pipe|, or accumulated in the profiled process depending on
+  // the |params.use_in_process_storage|.
+  // There is currently no mechanism to stop recording allocations.
   StartProfiling(ProfilingParams params);
 
   // Flushes the memlog pipe associated with this client. A barrier packet is
   // set over the memlog pipe with the given identifier. This allows the
   // receiver to synchronize with the flush.
   FlushMemlogPipe(uint32 barrier_id);
+
+  RetrieveHeapProfile() => (HeapProfile profile);
 };
diff --git a/components/sync/driver/resources/sync_log.js b/components/sync/driver/resources/sync_log.js
index 296a04a7..7b28f8a1 100644
--- a/components/sync/driver/resources/sync_log.js
+++ b/components/sync/driver/resources/sync_log.js
@@ -48,39 +48,36 @@
    * Creates a new log object which then immediately starts recording
    * sync events.  Recorded entries are available in the 'entries'
    * property and there is an 'append' event which can be listened to.
-   * @constructor
-   * @extends {cr.EventTarget}
    */
-  var Log = function() {
-    var self = this;
+  class Log extends cr.EventTarget {
+    constructor() {
+      super();
+      var self = this;
 
-    /**
-     * Creates a callback function to be invoked when an event arrives.
-     */
-    var makeCallback = function(categoryName, eventName) {
-      return function(e) {
-        self.log_(categoryName, eventName, e.details);
+      /**
+       * The recorded log entries.
+       * @type {array}
+       */
+      this.entries =  [];
+
+      /**
+       * Creates a callback function to be invoked when an event arrives.
+       */
+      var makeCallback = function(categoryName, eventName) {
+        return function(e) {
+          self.log_(categoryName, eventName, e.details);
+        };
       };
-    };
 
-    for (var categoryName in eventsByCategory) {
-      for (var i = 0; i < eventsByCategory[categoryName].length; ++i) {
-        var eventName = eventsByCategory[categoryName][i];
-        chrome.sync.events.addEventListener(
-            eventName,
-            makeCallback(categoryName, eventName));
+      for (var categoryName in eventsByCategory) {
+        for (var i = 0; i < eventsByCategory[categoryName].length; ++i) {
+          var eventName = eventsByCategory[categoryName][i];
+          chrome.sync.events.addEventListener(
+              eventName,
+              makeCallback(categoryName, eventName));
+        }
       }
     }
-  }
-
-  Log.prototype = {
-    __proto__: cr.EventTarget.prototype,
-
-    /**
-     * The recorded log entries.
-     * @type {array}
-     */
-    entries: [],
 
     /**
      * Records a single event with the given parameters and fires the
@@ -90,7 +87,7 @@
      * @param {string} event The name of the event.
      * @param {dictionary} details A dictionary of event-specific details.
      */
-    log_: function(submodule, event, details) {
+    log_(submodule, event, details) {
       var entry = {
         submodule: submodule,
         event: event,
@@ -105,7 +102,7 @@
       e.initCustomEvent('append', false, false, entry);
       this.dispatchEvent(e);
     }
-  };
+  }
 
   return {
     log: new Log()
diff --git a/components/translate_strings.grdp b/components/translate_strings.grdp
index d5ce108..ce817d8 100644
--- a/components/translate_strings.grdp
+++ b/components/translate_strings.grdp
@@ -72,13 +72,16 @@
   </message>
 
   <!-- Translate Notifications -->
-  <message name="IDS_TRANSLATE_NOTIFICATION_ALWAYS_TRANSLATE" desc="After the user selects 'Always translate pages in [source_language]', this text confirms the user's choice and lets them know that pages in [source_language] will be translated to the [target_language] automatically.">
+  <message name="IDS_TRANSLATE_NOTIFICATION_ERROR" desc="This text lets the user know that the page could not be translated.">
+    Oops. This page could not be translated.
+  </message>
+  <message name="IDS_TRANSLATE_NOTIFICATION_ALWAYS_TRANSLATE" desc="After the user selects 'Always translate [source_language]', this text confirms the user's choice and lets them know that pages in [source_language] will be translated to the [target_language] automatically.">
     Pages in <ph name="source_language">$1<ex>French</ex></ph> will be translated to <ph name="target_language">$2<ex>English</ex></ph> from now on.
   </message>
-  <message name="IDS_TRANSLATE_NOTIFICATION_LANGUAGE_NEVER" desc="After the user selects 'Never translate pages in [language]', this text confirms the user's choice and lets them know that pages in [language] will not be translated to their chosen target language automatically.">
+  <message name="IDS_TRANSLATE_NOTIFICATION_LANGUAGE_NEVER" desc="After the user selects 'Never translate [language]', this text confirms the user's choice and lets them know that pages in [language] will not be translated to their chosen target language automatically.">
     Pages in <ph name="language">$1<ex>French</ex></ph> will not be translated.
   </message>
-  <message name="IDS_TRANSLATE_NOTIFICATION_SITE_NEVER" desc="Text to be displayed in translate snackbar that lets the user know this site will not be translated.">
+  <message name="IDS_TRANSLATE_NOTIFICATION_SITE_NEVER" desc="After the user selects 'Never translate this site', this text confirms the user's choice and lets them know that this site will not be translated.">
     This site will not be translated.
   </message>
   <message name="IDS_TRANSLATE_NOTIFICATION_UNDO" desc="A text label on the translate snackbar widget to undo the this selection.">
diff --git a/components/viz/common/quads/render_pass.cc b/components/viz/common/quads/render_pass.cc
index b432ad9..b79ee8f 100644
--- a/components/viz/common/quads/render_pass.cc
+++ b/components/viz/common/quads/render_pass.cc
@@ -189,7 +189,7 @@
                         const gfx::Transform& transform_to_root_target,
                         const cc::FilterOperations& filters,
                         const cc::FilterOperations& backdrop_filters,
-                        const gfx::RectF& backdrop_filter_bounds,
+                        const gfx::RRectF& backdrop_filter_bounds,
                         const gfx::ColorSpace& color_space,
                         bool has_transparent_background,
                         bool cache_render_pass,
diff --git a/components/viz/common/quads/render_pass.h b/components/viz/common/quads/render_pass.h
index b4f42263..a967fb9 100644
--- a/components/viz/common/quads/render_pass.h
+++ b/components/viz/common/quads/render_pass.h
@@ -20,7 +20,7 @@
 #include "components/viz/common/viz_common_export.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/rrect_f.h"
 #include "ui/gfx/transform.h"
 
 namespace base {
@@ -91,7 +91,7 @@
               const gfx::Transform& transform_to_root_target,
               const cc::FilterOperations& filters,
               const cc::FilterOperations& backdrop_filters,
-              const gfx::RectF& backdrop_filter_bounds,
+              const gfx::RRectF& backdrop_filter_bounds,
               const gfx::ColorSpace& color_space,
               bool has_transparent_background,
               bool cache_render_pass,
@@ -131,7 +131,7 @@
   cc::FilterOperations backdrop_filters;
 
   // Clipping bounds for backdrop filter.
-  gfx::RectF backdrop_filter_bounds;
+  gfx::RRectF backdrop_filter_bounds;
 
   // The color space into which content will be rendered for this render pass.
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
diff --git a/components/viz/common/quads/render_pass_unittest.cc b/components/viz/common/quads/render_pass_unittest.cc
index 57e756f..9d106c7 100644
--- a/components/viz/common/quads/render_pass_unittest.cc
+++ b/components/viz/common/quads/render_pass_unittest.cc
@@ -29,7 +29,7 @@
   gfx::Transform transform_to_root_target;
   cc::FilterOperations filters;
   cc::FilterOperations backdrop_filters;
-  gfx::RectF backdrop_filter_bounds;
+  gfx::RRectF backdrop_filter_bounds;
   gfx::ColorSpace color_space;
   bool has_transparent_background;
   bool generate_mipmap;
@@ -82,7 +82,7 @@
   filters.Append(cc::FilterOperation::CreateOpacityFilter(0.5));
   cc::FilterOperations backdrop_filters;
   backdrop_filters.Append(cc::FilterOperation::CreateInvertFilter(1.0));
-  gfx::RectF backdrop_filter_bounds = gfx::RectF(10, 20, 130, 140);
+  gfx::RRectF backdrop_filter_bounds(10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8);
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
   bool has_transparent_background = true;
   bool cache_render_pass = false;
@@ -114,8 +114,8 @@
   EXPECT_EQ(pass->damage_rect, copy->damage_rect);
   EXPECT_EQ(pass->filters, copy->filters);
   EXPECT_EQ(pass->backdrop_filters, copy->backdrop_filters);
-  EXPECT_EQ(gfx::ToNearestRect(pass->backdrop_filter_bounds),
-            gfx::ToNearestRect(copy->backdrop_filter_bounds));
+  EXPECT_TRUE(pass->backdrop_filter_bounds.ApproximatelyEqual(
+      copy->backdrop_filter_bounds, 0.001));
   EXPECT_EQ(pass->has_transparent_background, copy->has_transparent_background);
   EXPECT_EQ(pass->generate_mipmap, copy->generate_mipmap);
   EXPECT_EQ(0u, copy->quad_list.size());
@@ -139,7 +139,7 @@
   filters.Append(cc::FilterOperation::CreateOpacityFilter(0.5));
   cc::FilterOperations backdrop_filters;
   backdrop_filters.Append(cc::FilterOperation::CreateInvertFilter(1.0));
-  gfx::RectF backdrop_filter_bounds = gfx::RectF(10, 20, 130, 140);
+  gfx::RRectF backdrop_filter_bounds(10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8);
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
   bool has_transparent_background = true;
   bool cache_render_pass = false;
@@ -192,7 +192,8 @@
   contrib_filters.Append(cc::FilterOperation::CreateSepiaFilter(0.5));
   cc::FilterOperations contrib_backdrop_filters;
   contrib_backdrop_filters.Append(cc::FilterOperation::CreateSaturateFilter(1));
-  gfx::RectF contrib_backdrop_filter_bounds = gfx::RectF(20, 30, 140, 150);
+  gfx::RRectF contrib_backdrop_filter_bounds(20, 30, 140, 150, 1, 2, 3, 4, 5, 6,
+                                             7, 8);
   gfx::ColorSpace contrib_color_space = gfx::ColorSpace::CreateSCRGBLinear();
   bool contrib_has_transparent_background = true;
   bool contrib_cache_render_pass = false;
@@ -247,7 +248,7 @@
   filters.Append(cc::FilterOperation::CreateOpacityFilter(0.5));
   cc::FilterOperations backdrop_filters;
   backdrop_filters.Append(cc::FilterOperation::CreateInvertFilter(1.0));
-  gfx::RectF backdrop_filter_bounds = gfx::RectF(10, 20, 130, 140);
+  gfx::RRectF backdrop_filter_bounds(10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8);
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateSCRGBLinear();
   bool has_transparent_background = true;
   bool cache_render_pass = false;
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index 0d4e3e86..2884259 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -508,7 +508,7 @@
   return it == render_pass_backdrop_filters_.end() ? nullptr : it->second;
 }
 
-const gfx::RectF* DirectRenderer::BackgroundFilterBoundsForPass(
+const gfx::RRectF* DirectRenderer::BackgroundFilterBoundsForPass(
     RenderPassId render_pass_id) const {
   auto it = render_pass_backdrop_filter_bounds_.find(render_pass_id);
   return it == render_pass_backdrop_filter_bounds_.end() ? nullptr : it->second;
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h
index 0ef6973c..c048c23 100644
--- a/components/viz/service/display/direct_renderer.h
+++ b/components/viz/service/display/direct_renderer.h
@@ -29,6 +29,7 @@
 
 namespace gfx {
 class ColorSpace;
+class RRectF;
 }
 
 namespace viz {
@@ -154,7 +155,7 @@
   const cc::FilterOperations* FiltersForPass(RenderPassId render_pass_id) const;
   const cc::FilterOperations* BackgroundFiltersForPass(
       RenderPassId render_pass_id) const;
-  const gfx::RectF* BackgroundFilterBoundsForPass(
+  const gfx::RRectF* BackgroundFilterBoundsForPass(
       RenderPassId render_pass_id) const;
 
   // Private interface implemented by subclasses for use by DirectRenderer.
@@ -235,7 +236,8 @@
   base::flat_map<RenderPassId, cc::FilterOperations*> render_pass_filters_;
   base::flat_map<RenderPassId, cc::FilterOperations*>
       render_pass_backdrop_filters_;
-  base::flat_map<RenderPassId, gfx::RectF*> render_pass_backdrop_filter_bounds_;
+  base::flat_map<RenderPassId, gfx::RRectF*>
+      render_pass_backdrop_filter_bounds_;
 
   bool visible_ = false;
   bool disable_color_checks_for_testing_ = false;
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index cc3d94f..57a2668 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -381,16 +381,6 @@
   // Run callbacks early to allow pipelining and collect presented callbacks.
   RunDrawCallbacks();
 
-  // Mark all the drawn surfaces, so that they can start receiving begin-frames.
-  const auto& undrawn_surfaces = aggregator_->undrawn_surfaces();
-  for (const auto& surface_id : aggregator_->previous_contained_surfaces()) {
-    if (undrawn_surfaces.count(surface_id.first))
-      continue;
-    Surface* surface = surface_manager_->GetSurfaceForId(surface_id.first);
-    if (surface)
-      surface->MarkAsDrawn();
-  }
-
   frame.metadata.latency_info.insert(frame.metadata.latency_info.end(),
                                      stored_latency_info_.begin(),
                                      stored_latency_info_.end());
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index efa4f77..ac89712 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -74,6 +74,7 @@
 #include "ui/gfx/geometry/quad_f.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/rrect_f.h"
 #include "ui/gfx/skia_util.h"
 
 using gpu::gles2::GLES2Interface;
@@ -212,7 +213,7 @@
   gfx::Transform quad_to_target_transform;
   const cc::FilterOperations* filters = nullptr;
   const cc::FilterOperations* backdrop_filters = nullptr;
-  const gfx::RectF* backdrop_filter_bounds = nullptr;
+  const gfx::RRectF* backdrop_filter_bounds = nullptr;
 
   // Whether the texture to be sampled from needs to be flipped.
   bool source_needs_flip = false;
@@ -715,10 +716,12 @@
     const cc::FilterOperations* filters,
     const cc::FilterOperations* backdrop_filters,
     const gfx::QuadF* clip_region,
-    const gfx::RectF* backdrop_filter_bounds_input,
+    const gfx::RRectF* backdrop_filter_bounds_input,
     bool use_aa,
-    gfx::Rect* backdrop_filter_bounds,
+    gfx::RRectF* backdrop_filter_bounds,
     gfx::Rect* unclipped_rect) {
+  DCHECK(backdrop_filter_bounds);
+  DCHECK(unclipped_rect);
   gfx::QuadF scaled_region;
   if (!GetScaledRegion(quad->rect, clip_region, &scaled_region)) {
     scaled_region = SharedGeometryQuad().BoundingBox();
@@ -732,10 +735,9 @@
   // was not found. For example, some GLRenderer tests can trigger this case,
   // e.g. GLRendererShaderTest.DrawRenderPassQuadShaderPermutations.
   if (backdrop_filter_bounds_input) {
-    *backdrop_filter_bounds =
-        gfx::ToEnclosingRect(*backdrop_filter_bounds_input);
+    *backdrop_filter_bounds = *backdrop_filter_bounds_input;
   } else {
-    *backdrop_filter_bounds = gfx::Rect();
+    *backdrop_filter_bounds = gfx::RRectF();
   }
 
   if (ShouldApplyBackgroundFilters(quad, backdrop_filters)) {
@@ -833,7 +835,7 @@
     const gfx::Rect& rect,
     const gfx::Rect& unclipped_rect,
     const float backdrop_filter_quality,
-    const gfx::Rect& backdrop_filter_bounds) {
+    const gfx::RRectF& backdrop_filter_bounds) {
   DCHECK(ShouldApplyBackgroundFilters(quad, backdrop_filters));
   auto use_gr_context = ScopedUseGrContext::Create(this);
 
@@ -915,13 +917,12 @@
       quad->filters_origin, true);
 
   if (!backdrop_filter_bounds.IsEmpty()) {
-    // Clip the filtered image to the bounding box of the element.
+    // Clip the filtered image to the (rounded) bounding box of the element.
     surface->getCanvas()->save();
-    gfx::RectF clip_rect_scaled = gfx::RectF(backdrop_filter_bounds);
-    clip_rect_scaled.Scale(backdrop_filter_quality);
-    SkRRect clip_rect =
-        SkRRect::MakeRectXY(RectFToSkRect(clip_rect_scaled), 0, 0);
-    surface->getCanvas()->clipRRect(clip_rect, SkClipOp::kIntersect,
+    gfx::RRectF clip_rect(backdrop_filter_bounds);
+    DCHECK(backdrop_filter_quality);
+    clip_rect.Scale(backdrop_filter_quality);
+    surface->getCanvas()->clipRRect(SkRRect(clip_rect), SkClipOp::kIntersect,
                                     true /* antialias */);
   }
 
@@ -1091,7 +1092,7 @@
   if (params->use_shaders_for_blending) {
     // Compute a bounding box around the pixels that will be visible through
     // the quad.
-    gfx::Rect backdrop_filter_bounds_rect;
+    gfx::RRectF backdrop_filter_bounds_rect;
     gfx::Rect unclipped_rect;
     params->background_rect = GetBackdropBoundingBoxForRenderPassQuad(
         quad, params->contents_device_transform, params->filters,
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h
index 6aa6806..299496a 100644
--- a/components/viz/service/display/gl_renderer.h
+++ b/components/viz/service/display/gl_renderer.h
@@ -41,6 +41,10 @@
 }
 }  // namespace gpu
 
+namespace gfx {
+class RRectF;
+}
+
 namespace viz {
 
 class DynamicGeometryBinding;
@@ -196,9 +200,9 @@
       const cc::FilterOperations* filters,
       const cc::FilterOperations* backdrop_filters,
       const gfx::QuadF* clip_region,
-      const gfx::RectF* backdrop_filter_bounds_input,
+      const gfx::RRectF* backdrop_filter_bounds_input,
       bool use_aa,
-      gfx::Rect* backdrop_filter_bounds,
+      gfx::RRectF* backdrop_filter_bounds,
       gfx::Rect* unclipped_rect);
   // Allocates and returns a texture id that contains a copy of the contents
   // of the current RenderPass being drawn.
@@ -223,7 +227,7 @@
       const gfx::Rect& rect,
       const gfx::Rect& unclipped_rect,
       const float backdrop_filter_quality,
-      const gfx::Rect& backdrop_filter_bounds);
+      const gfx::RRectF& backdrop_filter_bounds);
 
   const TileDrawQuad* CanPassBeDrawnDirectly(const RenderPass* pass) override;
 
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc
index 953f8109..127f1b74 100644
--- a/components/viz/service/display/renderer_pixeltest.cc
+++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -2637,7 +2637,7 @@
 
   RenderPassList pass_list_;
   cc::FilterOperations backdrop_filters_;
-  gfx::RectF backdrop_filter_bounds_;
+  gfx::RRectF backdrop_filter_bounds_;
   gfx::Transform filter_pass_to_target_transform_;
   gfx::Rect filter_pass_layer_rect_;
 };
@@ -2657,8 +2657,8 @@
   // so the clipping bounds should be 0,0 WxH, not
   // this->filter_pass_layer_rect_.
   this->backdrop_filter_bounds_ =
-      gfx::RectF(0, 0, this->filter_pass_layer_rect_.width(),
-                 this->filter_pass_layer_rect_.height());
+      gfx::RRectF(0, 0, this->filter_pass_layer_rect_.width(),
+                  this->filter_pass_layer_rect_.height(), 0);
   this->SetUpRenderPassList();
   EXPECT_TRUE(this->RunPixelTest(
       &this->pass_list_,
@@ -3081,7 +3081,7 @@
   std::unique_ptr<RenderPass> child_pass = RenderPass::Create();
   child_pass->SetAll(
       child_pass_id, child_pass_rect, child_pass_rect, transform_to_root,
-      cc::FilterOperations(), cc::FilterOperations(), gfx::RectF(),
+      cc::FilterOperations(), cc::FilterOperations(), gfx::RRectF(),
       gfx::ColorSpace::CreateSRGB(), false, false, false, generate_mipmap);
 
   gfx::Rect red_rect(child_pass_rect);
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index c4c88f8..c43c243 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -1112,6 +1112,7 @@
 
   Surface* surface = manager_->GetSurfaceForId(surface_id);
   DCHECK(surface);
+  DCHECK(contained_surfaces_.empty());
   contained_surfaces_[surface_id] = surface->GetActiveFrameIndex();
 
   LocalSurfaceId& local_surface_id =
@@ -1139,6 +1140,7 @@
   valid_surfaces_.clear();
   has_cached_render_passes_ = false;
   damage_ranges_.clear();
+  DCHECK(referenced_surfaces_.empty());
   PrewalkResult prewalk_result;
   root_damage_rect_ =
       PrewalkTree(surface, false, 0, true /* will_draw */, &prewalk_result);
@@ -1147,7 +1149,6 @@
   frame.metadata.may_contain_video = prewalk_result.may_contain_video;
 
   CopyUndrawnSurfaces(&prewalk_result);
-  undrawn_surfaces_ = std::move(prewalk_result.undrawn_surfaces);
   referenced_surfaces_.insert(surface_id);
   CopyPasses(root_surface_frame, surface);
   // CopyPasses may have mutated container, need to re-query to erase.
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h
index a7c22b39..335d6d28 100644
--- a/components/viz/service/display/surface_aggregator.h
+++ b/components/viz/service/display/surface_aggregator.h
@@ -51,12 +51,6 @@
   void SetFullDamageForSurface(const SurfaceId& surface_id);
   void set_output_is_secure(bool secure) { output_is_secure_ = secure; }
 
-  // The set of surfaces that are referenced, but do not contribute to the
-  // aggregated CompositorFrame.
-  const base::flat_set<SurfaceId>& undrawn_surfaces() const {
-    return undrawn_surfaces_;
-  }
-
   // Set the color spaces for the created RenderPasses, which is propagated
   // to the output surface.
   void SetOutputColorSpace(const gfx::ColorSpace& blending_color_space,
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index f361613..9c1d21e 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -764,17 +764,23 @@
                 const LocalSurfaceId& local_surface_id,
                 const gfx::Rect& bounds)
       : test_(test),
+        manager_(manager),
         frame_sink_id_(frame_sink_id),
         local_surface_id_(local_surface_id),
         bounds_(bounds) {
     constexpr bool is_root = false;
     constexpr bool needs_sync_points = false;
     support_ = std::make_unique<CompositorFrameSinkSupport>(
-        nullptr, manager, frame_sink_id, is_root, needs_sync_points);
+        nullptr, manager_, frame_sink_id, is_root, needs_sync_points);
   }
 
   ~TestVizClient() = default;
 
+  Surface* GetSurface() const {
+    return manager_->surface_manager()->GetSurfaceForId(
+        SurfaceId(frame_sink_id_, local_surface_id_));
+  }
+
   void SubmitCompositorFrame(SkColor bgcolor) {
     using Quad = SurfaceAggregatorValidSurfaceTest::Quad;
     using Pass = SurfaceAggregatorValidSurfaceTest::Pass;
@@ -818,6 +824,7 @@
 
  private:
   SurfaceAggregatorValidSurfaceTest* const test_;
+  FrameSinkManagerImpl* const manager_;
   std::unique_ptr<CompositorFrameSinkSupport> support_;
   const FrameSinkId frame_sink_id_;
   const LocalSurfaceId local_surface_id_;
@@ -868,8 +875,8 @@
   AggregateAndVerify(expected_passes, {root_surface_id, parent.surface_id(),
                                        child.surface_id()});
   // |child| should not be drawn.
-  EXPECT_THAT(aggregator_.undrawn_surfaces(),
-              ::testing::ElementsAre(child.surface_id()));
+  EXPECT_TRUE(child.GetSurface()->HasUndrawnActiveFrame());
+  EXPECT_FALSE(parent.GetSurface()->HasUndrawnActiveFrame());
 
   // Submit another CompositorFrame from |parent|, this time with a DrawQuad for
   // |child|.
@@ -883,7 +890,7 @@
   AggregateAndVerify(
       {Pass(expected_quads, SurfaceSize())},
       {root_surface_id, parent.surface_id(), child.surface_id()});
-  EXPECT_THAT(aggregator_.undrawn_surfaces(), ::testing::IsEmpty());
+  EXPECT_FALSE(child.GetSurface()->HasUndrawnActiveFrame());
 }
 
 TEST_F(SurfaceAggregatorValidSurfaceTest, UndrawnSurfacesWithCopyRequests) {
@@ -929,7 +936,76 @@
   SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   AggregateAndVerify(expected_passes, {root_surface_id, parent.surface_id(),
                                        child.surface_id()});
-  EXPECT_THAT(aggregator_.undrawn_surfaces(), ::testing::IsEmpty());
+  EXPECT_FALSE(child.GetSurface()->HasUndrawnActiveFrame());
+  EXPECT_FALSE(parent.GetSurface()->HasUndrawnActiveFrame());
+}
+
+TEST_F(SurfaceAggregatorValidSurfaceTest,
+       SurfacesWithMultipleEmbeddersBothVisibleAndInvisible) {
+  allocator_.GenerateId();
+  TestVizClient child(
+      this, &manager_, kArbitraryFrameSinkId1,
+      allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id(),
+      gfx::Rect(10, 10));
+  child.SubmitCompositorFrame(SK_ColorBLUE);
+
+  // First parent submits a CompositorFrame that renfereces |child|, but does
+  // not provide a DrawQuad that embeds it.
+  allocator_.GenerateId();
+  TestVizClient first_parent(
+      this, &manager_, kArbitraryFrameSinkId2,
+      allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id(),
+      gfx::Rect(15, 15));
+  first_parent.SetEmbeddedClient(&child, false);
+  first_parent.SubmitCompositorFrame(SK_ColorGREEN);
+
+  // Second parent submits a CompositorFrame referencing |child|, and also
+  // includes a draw-quad for it.
+  allocator_.GenerateId();
+  TestVizClient second_parent(
+      this, &manager_, kArbitraryMiddleFrameSinkId,
+      allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id(),
+      gfx::Rect(25, 25));
+  second_parent.SetEmbeddedClient(&child, true);
+  second_parent.SubmitCompositorFrame(SK_ColorYELLOW);
+
+  // Submit a root CompositorFrame that embeds both parents.
+  std::vector<Quad> root_quads = {
+      Quad::SolidColorQuad(SK_ColorWHITE, gfx::Rect(5, 5)),
+      Quad::SurfaceQuad(SurfaceRange(base::nullopt, first_parent.surface_id()),
+                        SK_ColorCYAN, first_parent.bounds(),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
+      Quad::SurfaceQuad(SurfaceRange(base::nullopt, second_parent.surface_id()),
+                        SK_ColorMAGENTA, second_parent.bounds(),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
+      Quad::SolidColorQuad(SK_ColorBLACK, gfx::Rect(5, 5))};
+  std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
+
+  constexpr float device_scale_factor = 1.0f;
+  SubmitCompositorFrame(support_.get(), root_passes, root_local_surface_id_,
+                        device_scale_factor);
+
+  EXPECT_TRUE(child.GetSurface()->HasUndrawnActiveFrame());
+  EXPECT_TRUE(first_parent.GetSurface()->HasUndrawnActiveFrame());
+  EXPECT_TRUE(second_parent.GetSurface()->HasUndrawnActiveFrame());
+
+  std::vector<Quad> expected_quads = {
+      Quad::SolidColorQuad(SK_ColorWHITE, gfx::Rect(5, 5)),
+      Quad::SolidColorQuad(SK_ColorGREEN, first_parent.bounds()),
+      Quad::SolidColorQuad(SK_ColorYELLOW, second_parent.bounds()),
+      Quad::SolidColorQuad(SK_ColorBLUE, gfx::Rect(10, 10)),
+      Quad::SolidColorQuad(SK_ColorBLACK, gfx::Rect(5, 5))};
+  std::vector<Quad> expected_copy_quads = {};
+  std::vector<Pass> expected_passes = {Pass(expected_quads, SurfaceSize())};
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
+  AggregateAndVerify(expected_passes,
+                     {root_surface_id, first_parent.surface_id(),
+                      second_parent.surface_id(), child.surface_id()});
+  EXPECT_FALSE(child.GetSurface()->HasUndrawnActiveFrame());
+  EXPECT_FALSE(first_parent.GetSurface()->HasUndrawnActiveFrame());
+  EXPECT_FALSE(second_parent.GetSurface()->HasUndrawnActiveFrame());
 }
 
 // This test verifies that in the absence of a primary Surface,
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index 0086e8a..ba137a4 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -346,9 +346,9 @@
 
   SkSurfaceCharacterization* characterization = nullptr;
   if (characterization_.isValid()) {
-    characterization_ = CreateSkSurfaceCharacterization(
-        gfx::Size(size.width(), size.height()), BGRA_8888, false,
-        color_space.ToSkColorSpace());
+    // TODO(weiliang): suppoot color space. https://crbug.com/795132
+    characterization_ =
+        characterization_.createResized(size.width(), size.height());
   } else {
     characterization = &characterization_;
     initialize_waitable_event_ = std::make_unique<base::WaitableEvent>(
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc
index b8b940f..fb8c3ea 100644
--- a/components/viz/service/surfaces/surface.cc
+++ b/components/viz/service/surfaces/surface.cc
@@ -600,6 +600,7 @@
     }
     render_pass->copy_requests.clear();
   }
+  MarkAsDrawn();
 }
 
 void Surface::TakeCopyOutputRequestsFromClient() {
@@ -757,6 +758,7 @@
         surface_info_.id().ToString());
   }
   surface_manager_->SurfaceWillBeDrawn(this);
+  MarkAsDrawn();
 }
 
 }  // namespace viz
diff --git a/components/viz/test/data/backdrop_filter_blur_rounded.png b/components/viz/test/data/backdrop_filter_blur_rounded.png
new file mode 100644
index 0000000..aa43e15
--- /dev/null
+++ b/components/viz/test/data/backdrop_filter_blur_rounded.png
Binary files differ
diff --git a/content/browser/accessibility/browser_accessibility_com_win.h b/content/browser/accessibility/browser_accessibility_com_win.h
index ff87a2ac..af665cd 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.h
+++ b/content/browser/accessibility/browser_accessibility_com_win.h
@@ -465,6 +465,8 @@
       base::string16* output);
   FRIEND_TEST_ALL_PREFIXES(BrowserAccessibilityTest,
                            TestSanitizeStringAttributeForIA2);
+  FRIEND_TEST_ALL_PREFIXES(BrowserAccessibilityWinTest,
+                           TestSanitizeStringAttributeForIA2);
 
   // Sets the selection given a start and end offset in IA2 Hypertext.
   void SetIA2HypertextSelection(LONG start_offset, LONG end_offset);
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc
index 576edda..16265eb 100644
--- a/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -28,38 +28,34 @@
 
 namespace content {
 
-// BrowserAccessibilityTest ---------------------------------------------------
+// BrowserAccessibilityWinTest ------------------------------------------------
 
-class BrowserAccessibilityTest : public testing::Test {
+class BrowserAccessibilityWinTest : public testing::Test {
  public:
-  BrowserAccessibilityTest();
-  ~BrowserAccessibilityTest() override;
+  BrowserAccessibilityWinTest();
+  ~BrowserAccessibilityWinTest() override;
 
  private:
   void SetUp() override;
-  
-  base::test::ScopedTaskEnvironment task_environment_;
+
   content::TestBrowserThreadBundle thread_bundle_;
 
-  DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityTest);
+  DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityWinTest);
 };
 
-BrowserAccessibilityTest::BrowserAccessibilityTest() {
-}
+BrowserAccessibilityWinTest::BrowserAccessibilityWinTest() {}
 
-BrowserAccessibilityTest::~BrowserAccessibilityTest() {
-}
+BrowserAccessibilityWinTest::~BrowserAccessibilityWinTest() {}
 
-void BrowserAccessibilityTest::SetUp() {
+void BrowserAccessibilityWinTest::SetUp() {
   ui::win::CreateATLModuleIfNeeded();
 }
 
-
 // Actual tests ---------------------------------------------------------------
 
 // Test that BrowserAccessibilityManager correctly releases the tree of
 // BrowserAccessibility instances upon delete.
-TEST_F(BrowserAccessibilityTest, TestNoLeaks) {
+TEST_F(BrowserAccessibilityWinTest, TestNoLeaks) {
   // Create ui::AXNodeData objects for a simple document tree,
   // representing the accessibility information used to initialize
   // BrowserAccessibilityManager.
@@ -118,7 +114,7 @@
   child1_iaccessible->Release();
 }
 
-TEST_F(BrowserAccessibilityTest, TestChildrenChange) {
+TEST_F(BrowserAccessibilityWinTest, TestChildrenChange) {
   // Create ui::AXNodeData objects for a simple document tree,
   // representing the accessibility information used to initialize
   // BrowserAccessibilityManager.
@@ -195,7 +191,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) {
+TEST_F(BrowserAccessibilityWinTest, TestChildrenChangeNoLeaks) {
   // Create ui::AXNodeData objects for a simple document tree,
   // representing the accessibility information used to initialize
   // BrowserAccessibilityManager.
@@ -241,7 +237,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestTextBoundaries) {
+TEST_F(BrowserAccessibilityWinTest, TestTextBoundaries) {
   std::string line1 = "One two three.";
   std::string line2 = "Four five six.";
   std::string text_value = line1 + '\n' + line2;
@@ -407,7 +403,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) {
+TEST_F(BrowserAccessibilityWinTest, TestSimpleHypertext) {
   const std::string text1_name = "One two three.";
   const std::string text2_name = " Four five six.";
   const LONG text_name_len = text1_name.length() + text2_name.length();
@@ -474,7 +470,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestComplexHypertext) {
+TEST_F(BrowserAccessibilityWinTest, TestComplexHypertext) {
   const base::string16 text1_name = L"One two three.";
   const base::string16 combo_box_name = L"City:";
   const base::string16 combo_box_value = L"Happyland";
@@ -629,7 +625,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestCreateEmptyDocument) {
+TEST_F(BrowserAccessibilityWinTest, TestCreateEmptyDocument) {
   // Try creating an empty document with busy state. Readonly is
   // set automatically.
   std::unique_ptr<BrowserAccessibilityManager> manager(
@@ -712,7 +708,7 @@
 // its UniqueIDWin, because the AX Tree was loaded in
 // BrowserAccessibilityManager code before BrowserAccessibilityManagerWin
 // was initialized.
-TEST_F(BrowserAccessibilityTest, EmptyDocHasUniqueIdWin) {
+TEST_F(BrowserAccessibilityWinTest, EmptyDocHasUniqueIdWin) {
   std::unique_ptr<BrowserAccessibilityManagerWin> manager(
       new BrowserAccessibilityManagerWin(
           BrowserAccessibilityManagerWin::GetEmptyDocument(), nullptr,
@@ -735,7 +731,7 @@
   ASSERT_EQ(node, other_node);
 }
 
-TEST_F(BrowserAccessibilityTest, TestIA2Attributes) {
+TEST_F(BrowserAccessibilityWinTest, TestIA2Attributes) {
   ui::AXNodeData pseudo_before;
   pseudo_before.id = 2;
   pseudo_before.role = ax::mojom::Role::kGenericContainer;
@@ -795,7 +791,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestValueAttributeInTextControls) {
+TEST_F(BrowserAccessibilityWinTest, TestValueAttributeInTextControls) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -938,7 +934,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestWordBoundariesInTextControls) {
+TEST_F(BrowserAccessibilityWinTest, TestWordBoundariesInTextControls) {
   const base::string16 line1(L"This is a very LONG line of text that ");
   const base::string16 line2(L"should wrap on more than one lines ");
   const base::string16 text(line1 + line2);
@@ -1101,7 +1097,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestCaretAndSelectionInSimpleFields) {
+TEST_F(BrowserAccessibilityWinTest, TestCaretAndSelectionInSimpleFields) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -1197,7 +1193,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestCaretInContentEditables) {
+TEST_F(BrowserAccessibilityWinTest, TestCaretInContentEditables) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -1318,7 +1314,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestSelectionInContentEditables) {
+TEST_F(BrowserAccessibilityWinTest, TestSelectionInContentEditables) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -1474,7 +1470,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestIAccessibleHyperlink) {
+TEST_F(BrowserAccessibilityWinTest, TestIAccessibleHyperlink) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -1635,7 +1631,7 @@
   EXPECT_EQ(7, end_index);
 }
 
-TEST_F(BrowserAccessibilityTest, TestTextAttributesInContentEditables) {
+TEST_F(BrowserAccessibilityWinTest, TestTextAttributesInContentEditables) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -1867,7 +1863,8 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestExistingMisspellingsInSimpleTextFields) {
+TEST_F(BrowserAccessibilityWinTest,
+       TestExistingMisspellingsInSimpleTextFields) {
   std::string value1("Testing .");
   // The word "helo" is misspelled.
   std::string value2("Helo there.");
@@ -1980,7 +1977,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestNewMisspellingsInSimpleTextFields) {
+TEST_F(BrowserAccessibilityWinTest, TestNewMisspellingsInSimpleTextFields) {
   std::string value1("Testing .");
   // The word "helo" is misspelled.
   std::string value2("Helo there.");
@@ -2104,7 +2101,7 @@
   manager.reset();
 }
 
-TEST_F(BrowserAccessibilityTest, TestDeepestFirstLastChild) {
+TEST_F(BrowserAccessibilityWinTest, TestDeepestFirstLastChild) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -2183,7 +2180,7 @@
   EXPECT_EQ(nullptr, child2_child2_accessible->InternalDeepestLastChild());
 }
 
-TEST_F(BrowserAccessibilityTest, TestInheritedStringAttributes) {
+TEST_F(BrowserAccessibilityWinTest, TestInheritedStringAttributes) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
@@ -2262,14 +2259,14 @@
                          ax::mojom::StringAttribute::kFontFamily));
 }
 
-TEST_F(BrowserAccessibilityTest, TestSanitizeStringAttributeForIA2) {
+TEST_F(BrowserAccessibilityWinTest, TestSanitizeStringAttributeForIA2) {
   base::string16 input(L"\\:=,;");
   base::string16 output;
   BrowserAccessibilityComWin::SanitizeStringAttributeForIA2(input, &output);
   EXPECT_EQ(L"\\\\\\:\\=\\,\\;", output);
 }
 
-TEST_F(BrowserAccessibilityTest, UniqueIdWinInvalidAfterDeletingTree) {
+TEST_F(BrowserAccessibilityWinTest, UniqueIdWinInvalidAfterDeletingTree) {
   ui::AXNodeData root_node;
   root_node.id = 1;
   root_node.role = ax::mojom::Role::kRootWebArea;
@@ -2328,7 +2325,7 @@
   EXPECT_EQ(S_OK, hr);
 }
 
-TEST_F(BrowserAccessibilityTest, AccChildOnlyReturnsDescendants) {
+TEST_F(BrowserAccessibilityWinTest, AccChildOnlyReturnsDescendants) {
   ui::AXNodeData root_node;
   root_node.id = 1;
   root_node.role = ax::mojom::Role::kRootWebArea;
@@ -2356,7 +2353,7 @@
                       child_unique_id_variant, result.GetAddressOf()));
 }
 
-TEST_F(BrowserAccessibilityTest, TestIAccessible2Relations) {
+TEST_F(BrowserAccessibilityWinTest, TestIAccessible2Relations) {
   ui::AXNodeData root;
   root.id = 1;
   root.role = ax::mojom::Role::kRootWebArea;
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index f90ca31..03898fd 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -762,7 +762,7 @@
 #if defined(OS_ANDROID)
   {
     TRACE_EVENT0("startup",
-                 "BrowserMainLoop::Subsystem:BrowserMediaPlayerManager");
+                 "BrowserMainLoop::Subsystem:ScopedSurfaceRequestManager");
     if (UsingInProcessGpu()) {
       gpu::ScopedSurfaceRequestConduit::SetInstance(
           ScopedSurfaceRequestManager::GetInstance());
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 6ba36d9..f5ffc8df 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -205,7 +205,7 @@
 
   // TODO(mkwst): Extract this logic out somewhere that can be shared between
   // Blink and //content.
-  if (IsSecMetadataEnabled()) {
+  if (IsSecMetadataEnabled() && IsOriginSecure(url)) {
     std::string site_value = "cross-site";
     if (initiator_origin) {
       url::Origin target_origin = url::Origin::Create(url);
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc
index 70c3213..beb09b1 100644
--- a/content/browser/media/android/browser_media_player_manager.cc
+++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -14,7 +14,6 @@
 #include "content/browser/media/android/media_web_contents_observer_android.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/media/media_player_messages_android.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
@@ -40,91 +39,30 @@
 
 namespace content {
 
-// Threshold on the number of media players per renderer before we start
-// attempting to release inactive media players.
-const int kMediaPlayerThreshold = 1;
-
-static BrowserMediaPlayerManager::Factory
-    g_browser_media_player_manager_factory = NULL;
-static media::MediaUrlInterceptor* media_url_interceptor_ = NULL;
-
 // static
 void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
-  // TODO(aberent) nullptr test is a temporary fix to simplify upstreaming Cast.
-  // Until Cast is fully upstreamed we want the downstream factory to take
-  // priority over the upstream factory. The downstream call happens first,
-  // so this will ensure that it does.
-  if (g_browser_media_player_manager_factory == nullptr)
-    g_browser_media_player_manager_factory = factory;
+  NOTREACHED();
 }
 
 // static
 void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
     media::MediaUrlInterceptor* media_url_interceptor) {
-  media_url_interceptor_ = media_url_interceptor;
+  // NOTREACHED() here causes some crashes in some test suites.
+  // This entire class will be removed very shortly in a follow up patch,
+  // so NO-OP is fine for now.
 }
 
 // static
 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
     RenderFrameHost* rfh) {
-  // In chrome, |g_browser_media_player_manager_factory| should be set
-  // to create a RemoteMediaPlayerManager, since RegisterFactory()
-  // should be called from
-  // ChromeMainDelegateAndroid::BasicStartupComplete.
-  //
-  // In webview, no factory should be set, and returning a nullptr should be
-  // handled by the caller.
-  return g_browser_media_player_manager_factory != nullptr
-             ? g_browser_media_player_manager_factory(rfh)
-             : nullptr;
+  NOTREACHED();
+  return nullptr;
 }
 
 std::unique_ptr<MediaPlayerAndroid>
 BrowserMediaPlayerManager::CreateMediaPlayer(
     const MediaPlayerHostMsg_Initialize_Params& media_player_params,
     bool hide_url_log) {
-  switch (media_player_params.type) {
-    case MEDIA_PLAYER_TYPE_REMOTE_ONLY:
-    case MEDIA_PLAYER_TYPE_URL: {
-      const std::string user_agent =
-          GetContentClient()->browser()->GetUserAgent();
-      auto media_player_bridge = std::make_unique<MediaPlayerBridge>(
-          media_player_params.player_id, media_player_params.url,
-          media_player_params.site_for_cookies, user_agent, hide_url_log, this,
-          base::Bind(&BrowserMediaPlayerManager::OnDecoderResourcesReleased,
-                     weak_ptr_factory_.GetWeakPtr()),
-          media_player_params.frame_url, media_player_params.allow_credentials);
-
-      if (media_player_params.type == MEDIA_PLAYER_TYPE_REMOTE_ONLY)
-        return std::move(media_player_bridge);
-
-      bool should_block = false;
-      bool extract_metadata =
-          // Initialize the player will cause MediaMetadataExtractor to decode
-          // small chunks of data.
-          RequestDecoderResources(media_player_params.player_id, true);
-#if !defined(USE_AURA)
-      if (WebContentsDelegate* delegate = web_contents_->GetDelegate()) {
-        should_block =
-            delegate->ShouldBlockMediaRequest(media_player_params.url);
-      } else {
-        extract_metadata = false;
-      }
-#endif
-      if (!extract_metadata) {
-        // May reach here due to prerendering or throttling. Don't extract the
-        // metadata since it is expensive.
-        // TODO(qinmin): extract the metadata once the user decided to load
-        // the page.
-        OnMediaMetadataChanged(media_player_params.player_id, base::TimeDelta(),
-                               0, 0, false);
-      } else if (!should_block) {
-        media_player_bridge->Initialize();
-      }
-      return std::move(media_player_bridge);
-    }
-  }
-
   NOTREACHED();
   return nullptr;
 }
@@ -137,290 +75,184 @@
 }
 
 BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {
-  // During the tear down process, OnDestroyPlayer() may or may not be called
-  // (e.g. the WebContents may be destroyed before the render process). So
-  // we cannot DCHECK(players_.empty()) here. Instead, all media players in
-  // |players_| will be destroyed here because |player_| is a
-  // std::vector<std::unique_ptr<>>.
-
-  for (auto& player : players_)
-    player.release()->DeleteOnCorrectThread();
-
-  players_.clear();
 }
 
 void BrowserMediaPlayerManager::OnTimeUpdate(
     int player_id,
     base::TimeDelta current_timestamp,
     base::TimeTicks current_time_ticks) {
-  Send(new MediaPlayerMsg_MediaTimeUpdate(
-      RoutingID(), player_id, current_timestamp, current_time_ticks));
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnMediaMetadataChanged(
     int player_id, base::TimeDelta duration, int width, int height,
     bool success) {
-  Send(new MediaPlayerMsg_MediaMetadataChanged(
-      RoutingID(), player_id, duration, width, height, success));
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) {
-  Send(new MediaPlayerMsg_MediaPlaybackCompleted(RoutingID(), player_id));
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) {
   // Tell WebKit that the audio should be paused, then release all resources
-  Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(), player_id));
-  ReleaseResources(player_id);
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnBufferingUpdate(int player_id,
                                                   int percentage) {
-  Send(new MediaPlayerMsg_MediaBufferingUpdate(RoutingID(), player_id,
-                                               percentage));
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnSeekRequest(
     int player_id,
     const base::TimeDelta& time_to_seek) {
-  Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek));
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnSeekComplete(
     int player_id,
     const base::TimeDelta& current_time) {
-  Send(new MediaPlayerMsg_SeekCompleted(RoutingID(), player_id, current_time));
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnError(int player_id, int error) {
-  Send(new MediaPlayerMsg_MediaError(RoutingID(), player_id, error));
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnVideoSizeChanged(
     int player_id, int width, int height) {
-  Send(new MediaPlayerMsg_MediaVideoSizeChanged(RoutingID(), player_id,
-      width, height));
+  NOTREACHED();
 }
 
 media::MediaResourceGetter*
 BrowserMediaPlayerManager::GetMediaResourceGetter() {
-  if (!media_resource_getter_.get()) {
-    RenderProcessHost* host = web_contents()->GetMainFrame()->GetProcess();
-    BrowserContext* context = host->GetBrowserContext();
-    StoragePartition* partition = host->GetStoragePartition();
-    storage::FileSystemContext* file_system_context =
-        partition ? partition->GetFileSystemContext() : NULL;
-    // Eventually this needs to be fixed to pass the correct frame rather
-    // than just using the main frame.
-    media_resource_getter_.reset(new MediaResourceGetterImpl(
-        context,
-        file_system_context,
-        host->GetID(),
-        web_contents()->GetMainFrame()->GetRoutingID()));
-  }
-  return media_resource_getter_.get();
+  NOTREACHED();
+  return nullptr;
 }
 
 media::MediaUrlInterceptor*
 BrowserMediaPlayerManager::GetMediaUrlInterceptor() {
-  return media_url_interceptor_;
+  NOTREACHED();
+  return nullptr;
 }
 
 MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
-  for (const auto& player : players_) {
-    if (player->player_id() == player_id)
-      return player.get();
-  }
+  NOTREACHED();
   return nullptr;
 }
 
 bool BrowserMediaPlayerManager::RequestPlay(int player_id,
                                             base::TimeDelta duration,
                                             bool has_audio) {
-  DCHECK(player_id_to_delegate_id_map_.find(player_id) !=
-         player_id_to_delegate_id_map_.end());
-  return MediaWebContentsObserverAndroid::FromWebContents(web_contents_)
-      ->RequestPlay(render_frame_host_,
-                    player_id_to_delegate_id_map_[player_id], has_audio,
-                    IsPlayingRemotely(player_id),
-                    media::DurationToMediaContentType(duration));
+  NOTREACHED();
+  return false;
 }
 
 void BrowserMediaPlayerManager::OnInitialize(
     const MediaPlayerHostMsg_Initialize_Params& media_player_params) {
-  DestroyPlayer(media_player_params.player_id);
-
-  bool is_off_the_record =
-      web_contents()->GetBrowserContext()->IsOffTheRecord();
-  auto player = CreateMediaPlayer(media_player_params, is_off_the_record);
-  if (!player)
-    return;
-
-  AddPlayer(std::move(player), media_player_params.delegate_id);
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnStart(int player_id) {
-  MediaPlayerAndroid* player = GetPlayer(player_id);
-  if (!player)
-    return;
-
-  RequestDecoderResources(player_id, false);
-
-  player->Start();
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnSeek(
     int player_id,
     const base::TimeDelta& time) {
-  MediaPlayerAndroid* player = GetPlayer(player_id);
-  if (player)
-    player->SeekTo(time);
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnPause(
     int player_id,
     bool is_media_related_action) {
-  MediaPlayerAndroid* player = GetPlayer(player_id);
-  if (player)
-    player->Pause(is_media_related_action);
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
-  MediaPlayerAndroid* player = GetPlayer(player_id);
-  if (player)
-    player->SetVolume(volume);
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
-  // To be overridden by subclasses.
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnSuspendAndReleaseResources(int player_id) {
-  ReleaseResources(player_id);
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
-  DestroyPlayer(player_id);
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnRequestRemotePlayback(int /* player_id */) {
-  // Does nothing if we don't have a remote player
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnRequestRemotePlaybackControl(
     int /* player_id */) {
-  // Does nothing if we don't have a remote player
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::OnRequestRemotePlaybackStop(
     int /* player_id */) {
-  // Does nothing if we don't have a remote player
+  NOTREACHED();
 }
 
 bool BrowserMediaPlayerManager::IsPlayingRemotely(int player_id) {
+  NOTREACHED();
   return false;
 }
 
 void BrowserMediaPlayerManager::AddPlayer(
     std::unique_ptr<MediaPlayerAndroid> player,
     int delegate_id) {
-  DCHECK(!GetPlayer(player->player_id()));
-  players_.push_back(std::move(player));
-  player_id_to_delegate_id_map_[players_.back()->player_id()] = delegate_id;
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::DestroyPlayer(int player_id) {
-  for (auto it = players_.begin(); it != players_.end(); ++it) {
-    if ((*it)->player_id() == player_id) {
-      it->release()->DeleteOnCorrectThread();
-      players_.erase(it);
-      break;
-    }
-  }
-  active_players_.erase(player_id);
-  player_id_to_delegate_id_map_.erase(player_id);
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::ReleaseResources(int player_id) {
-  MediaPlayerAndroid* player = GetPlayer(player_id);
-  if (player)
-    ReleasePlayer(player);
+  NOTREACHED();
 }
 
 std::unique_ptr<MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
     int player_id,
     std::unique_ptr<MediaPlayerAndroid> player) {
-  std::unique_ptr<MediaPlayerAndroid> previous_player;
-  for (auto it = players_.begin(); it != players_.end(); ++it) {
-    if ((*it)->player_id() == player_id) {
-      previous_player = std::move(*it);
-      MediaWebContentsObserverAndroid::FromWebContents(web_contents_)
-          ->DisconnectMediaSession(render_frame_host_,
-                                   player_id_to_delegate_id_map_[player_id]);
-      players_.erase(it);
-      players_.push_back(std::move(player));
-      break;
-    }
-  }
-  return previous_player;
+  NOTREACHED();
+  return nullptr;
 }
 
 bool BrowserMediaPlayerManager::RequestDecoderResources(
     int player_id, bool temporary) {
-  ActivePlayerMap::iterator it;
-  // The player is already active, ignore it. A long running player should not
-  // request temporary permissions.
-  if ((it = active_players_.find(player_id)) != active_players_.end()) {
-    DCHECK(!temporary || it->second);
-    return true;
-  }
-
-  if (!temporary) {
-    int long_running_player = 0;
-    for (it = active_players_.begin(); it != active_players_.end(); ++it) {
-      if (!it->second)
-        long_running_player++;
-    }
-
-    // Number of active players are less than the threshold, do nothing.
-    if (long_running_player < kMediaPlayerThreshold)
-      return true;
-
-    for (it = active_players_.begin(); it != active_players_.end(); ++it) {
-      if (!it->second && !GetPlayer(it->first)->IsPlaying()) {
-        ReleasePlayer(GetPlayer(it->first));
-        Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(),
-                                                    (it->first)));
-      }
-    }
-  }
-
-  active_players_[player_id] = temporary;
+  NOTREACHED();
   return true;
 }
 
 void BrowserMediaPlayerManager::OnDecoderResourcesReleased(int player_id) {
-  if (active_players_.find(player_id) == active_players_.end())
-    return;
-
-  active_players_.erase(player_id);
+  NOTREACHED();
 }
 
 int BrowserMediaPlayerManager::RoutingID() {
-  return render_frame_host_->GetRoutingID();
+  NOTREACHED();
+  return 0;
 }
 
 bool BrowserMediaPlayerManager::Send(IPC::Message* msg) {
+  NOTREACHED();
   return render_frame_host_->Send(msg);
 }
 
 void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
     MediaPlayerAndroid* player) {
-  ReleasePlayer(player);
+  NOTREACHED();
 }
 
 void BrowserMediaPlayerManager::ReleasePlayer(MediaPlayerAndroid* player) {
-  player->Release();
+  NOTREACHED();
 }
 
 }  // namespace content
diff --git a/content/browser/media/android/media_web_contents_observer_android.cc b/content/browser/media/android/media_web_contents_observer_android.cc
index a3974314..4810676 100644
--- a/content/browser/media/android/media_web_contents_observer_android.cc
+++ b/content/browser/media/android/media_web_contents_observer_android.cc
@@ -8,10 +8,8 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
-#include "content/browser/media/android/browser_media_player_manager.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/media/media_player_delegate_messages.h"
-#include "content/common/media/media_player_messages_android.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "ipc/ipc_message_macros.h"
@@ -39,109 +37,8 @@
           ->media_web_contents_observer());
 }
 
-BrowserMediaPlayerManager*
-MediaWebContentsObserverAndroid::GetMediaPlayerManager(
-    RenderFrameHost* render_frame_host) {
-  auto it = media_player_managers_.find(render_frame_host);
-  if (it != media_player_managers_.end())
-    return it->second.get();
-
-  BrowserMediaPlayerManager* manager =
-      BrowserMediaPlayerManager::Create(render_frame_host);
-  media_player_managers_[render_frame_host] = base::WrapUnique(manager);
-  return manager;
-}
-
 void MediaWebContentsObserverAndroid::SuspendAllMediaPlayers() {
   web_contents()->ForEachFrame(
       base::BindRepeating(&SuspendAllMediaPlayersInRenderFrame));
 }
-
-bool MediaWebContentsObserverAndroid::RequestPlay(
-    RenderFrameHost* render_frame_host,
-    int delegate_id,
-    bool has_audio,
-    bool is_remote,
-    media::MediaContentType media_content_type) {
-  return session_controllers_manager()->RequestPlay(
-      MediaPlayerId(render_frame_host, delegate_id), has_audio, is_remote,
-      media_content_type);
-}
-
-void MediaWebContentsObserverAndroid::DisconnectMediaSession(
-    RenderFrameHost* render_frame_host,
-    int delegate_id) {
-  session_controllers_manager()->OnEnd(
-      MediaPlayerId(render_frame_host, delegate_id));
-}
-
-void MediaWebContentsObserverAndroid::RenderFrameDeleted(
-    RenderFrameHost* render_frame_host) {
-  MediaWebContentsObserver::RenderFrameDeleted(render_frame_host);
-
-  media_player_managers_.erase(render_frame_host);
-}
-
-bool MediaWebContentsObserverAndroid::OnMessageReceived(
-    const IPC::Message& msg,
-    RenderFrameHost* render_frame_host) {
-  if (MediaWebContentsObserver::OnMessageReceived(msg, render_frame_host))
-    return true;
-
-  if (OnMediaPlayerMessageReceived(msg, render_frame_host))
-    return true;
-
-  return false;
-}
-
-bool MediaWebContentsObserverAndroid::OnMediaPlayerMessageReceived(
-    const IPC::Message& msg,
-    RenderFrameHost* render_frame_host) {
-  // The only BMPM instance that is still currently used is the
-  // RemoteMediaPlayerManager, used in casting.
-  //
-  // In the webview case, casting is not supported, and GetMediaPlayerManager()
-  // will return a nullptr. It is safe to not handle the messages, since the
-  // only message we can receive is an unavoidable MediaPlayerHostMsg_Initialize
-  // that WMPI sends out in WebMediaPlayerImpl::DoLoad().
-  BrowserMediaPlayerManager* media_player_manager =
-      GetMediaPlayerManager(render_frame_host);
-
-  if (!media_player_manager)
-    return false;
-
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserverAndroid, msg)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Initialize, media_player_manager,
-                        BrowserMediaPlayerManager::OnInitialize)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Start, media_player_manager,
-                        BrowserMediaPlayerManager::OnStart)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Seek, media_player_manager,
-                        BrowserMediaPlayerManager::OnSeek)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Pause, media_player_manager,
-                        BrowserMediaPlayerManager::OnPause)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SetVolume, media_player_manager,
-                        BrowserMediaPlayerManager::OnSetVolume)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SetPoster, media_player_manager,
-                        BrowserMediaPlayerManager::OnSetPoster)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SuspendAndRelease,
-                        media_player_manager,
-                        BrowserMediaPlayerManager::OnSuspendAndReleaseResources)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_DestroyMediaPlayer,
-                        media_player_manager,
-                        BrowserMediaPlayerManager::OnDestroyPlayer)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_RequestRemotePlayback,
-                        media_player_manager,
-                        BrowserMediaPlayerManager::OnRequestRemotePlayback)
-    IPC_MESSAGE_FORWARD(
-        MediaPlayerHostMsg_RequestRemotePlaybackControl, media_player_manager,
-        BrowserMediaPlayerManager::OnRequestRemotePlaybackControl)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_RequestRemotePlaybackStop,
-                        media_player_manager,
-                        BrowserMediaPlayerManager::OnRequestRemotePlaybackStop)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
 }  // namespace content
diff --git a/content/browser/media/android/media_web_contents_observer_android.h b/content/browser/media/android/media_web_contents_observer_android.h
index 13da22f..f09839ade 100644
--- a/content/browser/media/android/media_web_contents_observer_android.h
+++ b/content/browser/media/android/media_web_contents_observer_android.h
@@ -20,8 +20,6 @@
 
 namespace content {
 
-class BrowserMediaPlayerManager;
-
 // This class adds Android specific extensions to the MediaWebContentsObserver.
 class CONTENT_EXPORT MediaWebContentsObserverAndroid
     : public MediaWebContentsObserver {
@@ -33,48 +31,12 @@
   static MediaWebContentsObserverAndroid* FromWebContents(
       WebContents* web_contents);
 
-  // Gets one of the managers associated with the given |render_frame_host|.
-  // Creates a new one if it doesn't exist. The caller doesn't own the
-  // returned pointer.
-  BrowserMediaPlayerManager* GetMediaPlayerManager(
-      RenderFrameHost* render_frame_host);
-
   // Called by the WebContents when a tab has been closed but may still be
   // available for "undo" -- indicates that all media players (even audio only
   // players typically allowed background audio) bound to this WebContents must
   // be suspended.
   void SuspendAllMediaPlayers();
-
-  // Initiates a synchronous MediaSession request for browser side players.
-  //
-  // TODO(dalecurtis): Delete this method once we're no longer using WMPA and
-  // the BrowserMediaPlayerManagers.  Tracked by http://crbug.com/580626
-  bool RequestPlay(RenderFrameHost* render_frame_host,
-                   int delegate_id,
-                   bool has_audio,
-                   bool is_remote,
-                   media::MediaContentType media_content_type);
-
-  void DisconnectMediaSession(RenderFrameHost* render_frame_host,
-                              int delegate_id);
-
-  // MediaWebContentsObserver overrides.
-  void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
-  bool OnMessageReceived(const IPC::Message& message,
-                         RenderFrameHost* render_frame_host) override;
-
  private:
-  // Helper functions to handle media player IPC messages. Returns whether the
-  // |message| is handled in the function.
-  bool OnMediaPlayerMessageReceived(const IPC::Message& message,
-                                    RenderFrameHost* render_frame_host);
-
-  // Map from RenderFrameHost* to BrowserMediaPlayerManager.
-  using MediaPlayerManagerMap =
-      std::unordered_map<RenderFrameHost*,
-                         std::unique_ptr<BrowserMediaPlayerManager>>;
-  MediaPlayerManagerMap media_player_managers_;
-
   DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserverAndroid);
 };
 
diff --git a/content/browser/media/session/media_session_android.cc b/content/browser/media/session/media_session_android.cc
index fd2f481..0204354 100644
--- a/content/browser/media/session/media_session_android.cc
+++ b/content/browser/media/session/media_session_android.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/media/session/media_session_android.h"
 
+#include <utility>
+
 #include "base/android/jni_array.h"
 #include "base/time/time.h"
 #include "content/browser/media/session/media_session_impl.h"
@@ -26,7 +28,9 @@
 };
 
 MediaSessionAndroid::MediaSessionAndroid(MediaSessionImpl* session)
-    : MediaSessionObserver(session) {
+    : media_session_(session) {
+  DCHECK(media_session_);
+
   JNIEnv* env = base::android::AttachCurrentThread();
   ScopedJavaLocalRef<jobject> j_media_session =
       Java_MediaSessionImpl_create(env, reinterpret_cast<intptr_t>(this));
@@ -35,9 +39,26 @@
   WebContentsAndroid* contents_android = GetWebContentsAndroid();
   if (contents_android)
     contents_android->SetMediaSession(j_media_session);
+
+  media_session::mojom::MediaSessionObserverPtr observer;
+  observer_binding_.Bind(mojo::MakeRequest(&observer));
+  session->AddObserver(std::move(observer));
 }
 
-MediaSessionAndroid::~MediaSessionAndroid() = default;
+MediaSessionAndroid::~MediaSessionAndroid() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> j_local_session = j_media_session_.get(env);
+
+  // The Java object will tear down after this call.
+  if (!j_local_session.is_null())
+    Java_MediaSessionImpl_mediaSessionDestroyed(env, j_local_session);
+
+  j_media_session_.reset();
+
+  WebContentsAndroid* contents_android = GetWebContentsAndroid();
+  if (contents_android)
+    contents_android->SetMediaSession(nullptr);
+}
 
 // static
 ScopedJavaLocalRef<jobject> JNI_MediaSessionImpl_GetMediaSessionFromWebContents(
@@ -53,30 +74,17 @@
       session->session_android());
 }
 
-void MediaSessionAndroid::MediaSessionDestroyed() {
+void MediaSessionAndroid::MediaSessionInfoChanged(
+    media_session::mojom::MediaSessionInfoPtr session_info) {
   ScopedJavaLocalRef<jobject> j_local_session = GetJavaObject();
   if (j_local_session.is_null())
     return;
 
   JNIEnv* env = base::android::AttachCurrentThread();
-  // The Java object will tear down after this call.
-  Java_MediaSessionImpl_mediaSessionDestroyed(env, j_local_session);
-  j_media_session_.reset();
-
-  WebContentsAndroid* contents_android = GetWebContentsAndroid();
-  if (contents_android)
-    contents_android->SetMediaSession(nullptr);
-}
-
-void MediaSessionAndroid::MediaSessionStateChanged(bool is_controllable,
-                                                   bool is_suspended) {
-  ScopedJavaLocalRef<jobject> j_local_session = GetJavaObject();
-  if (j_local_session.is_null())
-    return;
-
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_MediaSessionImpl_mediaSessionStateChanged(env, j_local_session,
-                                                 is_controllable, is_suspended);
+  Java_MediaSessionImpl_mediaSessionStateChanged(
+      env, j_local_session, session_info->is_controllable,
+      session_info->playback_state ==
+          media_session::mojom::MediaPlaybackState::kPaused);
 }
 
 void MediaSessionAndroid::MediaSessionMetadataChanged(
@@ -99,7 +107,7 @@
 }
 
 void MediaSessionAndroid::MediaSessionActionsChanged(
-    const std::set<media_session::mojom::MediaSessionAction>& actions) {
+    const std::vector<media_session::mojom::MediaSessionAction>& actions) {
   ScopedJavaLocalRef<jobject> j_local_session = GetJavaObject();
   if (j_local_session.is_null())
     return;
@@ -116,55 +124,52 @@
 void MediaSessionAndroid::Resume(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& j_obj) {
-  DCHECK(media_session());
-  media_session()->Resume(MediaSession::SuspendType::kUI);
+  DCHECK(media_session_);
+  media_session_->Resume(MediaSession::SuspendType::kUI);
 }
 
 void MediaSessionAndroid::Suspend(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& j_obj) {
-  DCHECK(media_session());
-  media_session()->Suspend(MediaSession::SuspendType::kUI);
+  DCHECK(media_session_);
+  media_session_->Suspend(MediaSession::SuspendType::kUI);
 }
 
 void MediaSessionAndroid::Stop(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& j_obj) {
-  DCHECK(media_session());
-  media_session()->Stop(MediaSession::SuspendType::kUI);
+  DCHECK(media_session_);
+  media_session_->Stop(MediaSession::SuspendType::kUI);
 }
 
 void MediaSessionAndroid::Seek(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& j_obj,
     const jlong millis) {
-  DCHECK(media_session());
+  DCHECK(media_session_);
   DCHECK_NE(millis, 0)
       << "Attempted to seek by a missing number of milliseconds";
-  media_session()->Seek(base::TimeDelta::FromMilliseconds(millis));
+  media_session_->Seek(base::TimeDelta::FromMilliseconds(millis));
 }
 
 void MediaSessionAndroid::DidReceiveAction(JNIEnv* env,
                                            const JavaParamRef<jobject>& obj,
                                            int action) {
-  media_session()->DidReceiveAction(
+  media_session_->DidReceiveAction(
       static_cast<media_session::mojom::MediaSessionAction>(action));
 }
 
 void MediaSessionAndroid::RequestSystemAudioFocus(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& j_obj) {
-  DCHECK(media_session());
-  static_cast<MediaSessionImpl*>(media_session())
-      ->RequestSystemAudioFocus(media_session::mojom::AudioFocusType::kGain);
+  DCHECK(media_session_);
+  media_session_->RequestSystemAudioFocus(
+      media_session::mojom::AudioFocusType::kGain);
 }
 
 WebContentsAndroid* MediaSessionAndroid::GetWebContentsAndroid() {
-  MediaSessionImpl* session = static_cast<MediaSessionImpl*>(media_session());
-  if (!session)
-    return nullptr;
   WebContentsImpl* contents =
-      static_cast<WebContentsImpl*>(session->web_contents());
+      static_cast<WebContentsImpl*>(media_session_->web_contents());
   if (!contents)
     return nullptr;
   return contents->GetWebContentsAndroid();
diff --git a/content/browser/media/session/media_session_android.h b/content/browser/media/session/media_session_android.h
index 21d4b2a..241fa69 100644
--- a/content/browser/media/session/media_session_android.h
+++ b/content/browser/media/session/media_session_android.h
@@ -11,7 +11,8 @@
 
 #include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
-#include "content/public/browser/media_session_observer.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/media_session/public/mojom/media_session.mojom.h"
 
 namespace content {
 
@@ -22,7 +23,8 @@
 // MediaSession. This class is owned by the native MediaSession and will
 // teardown Java MediaSession when the native MediaSession is destroyed.
 // Java MediaSessionObservers are also proxied via this class.
-class MediaSessionAndroid final : public MediaSessionObserver {
+class MediaSessionAndroid final
+    : public media_session::mojom::MediaSessionObserver {
  public:
   // Helper class for calling GetJavaObject() in a static method, in order to
   // avoid leaking the Java object outside.
@@ -31,14 +33,13 @@
   explicit MediaSessionAndroid(MediaSessionImpl* session);
   ~MediaSessionAndroid() override;
 
-  // MediaSessionObserver implementation.
-  void MediaSessionDestroyed() override;
-  void MediaSessionStateChanged(bool is_controllable,
-                                bool is_suspended) override;
+  // media_session::mojom::MediaSessionObserver implementation:
+  void MediaSessionInfoChanged(
+      media_session::mojom::MediaSessionInfoPtr session_info) override;
   void MediaSessionMetadataChanged(
       const base::Optional<media_session::MediaMetadata>& metadata) override;
   void MediaSessionActionsChanged(
-      const std::set<media_session::mojom::MediaSessionAction>& actions)
+      const std::vector<media_session::mojom::MediaSessionAction>& action)
       override;
 
   // MediaSession method wrappers.
@@ -64,6 +65,11 @@
   // to avoid introducing a new GC root.
   JavaObjectWeakGlobalRef j_media_session_;
 
+  MediaSessionImpl* const media_session_;
+
+  mojo::Binding<media_session::mojom::MediaSessionObserver> observer_binding_{
+      this};
+
   DISALLOW_COPY_AND_ASSIGN(MediaSessionAndroid);
 };
 
diff --git a/content/browser/media/session/media_session_impl_browsertest.cc b/content/browser/media/session/media_session_impl_browsertest.cc
index e7a23dc..83085ccc 100644
--- a/content/browser/media/session/media_session_impl_browsertest.cc
+++ b/content/browser/media/session/media_session_impl_browsertest.cc
@@ -17,7 +17,6 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "content/browser/media/session/audio_focus_delegate.h"
-#include "content/browser/media/session/mock_media_session_observer.h"
 #include "content/browser/media/session/mock_media_session_player_observer.h"
 #include "content/browser/media/session/mock_media_session_service_impl.h"
 #include "content/public/browser/media_session.h"
@@ -41,6 +40,8 @@
 using content::MockMediaSessionPlayerObserver;
 
 using media_session::mojom::AudioFocusType;
+using media_session::mojom::MediaPlaybackState;
+using media_session::mojom::MediaSessionInfo;
 
 using ::testing::Eq;
 using ::testing::Expectation;
@@ -118,8 +119,6 @@
         shell(), embedded_test_server()->GetURL("example.com", "/title1.html"));
 
     media_session_ = MediaSessionImpl::Get(shell()->web_contents());
-    mock_media_session_observer_.reset(
-        new NiceMock<content::MockMediaSessionObserver>(media_session_));
     mock_audio_focus_delegate_ = new NiceMock<MockAudioFocusDelegate>(
         media_session_, true /* async_mode */);
     media_session_->SetDelegateForTests(
@@ -128,7 +127,6 @@
   }
 
   void TearDownOnMainThread() override {
-    mock_media_session_observer_.reset();
     media_session_->RemoveAllPlayersForTest();
     mock_media_session_service_.reset();
 
@@ -223,16 +221,13 @@
     return mock_audio_focus_delegate()->HasRequests();
   }
 
-  content::MockMediaSessionObserver* mock_media_session_observer() {
-    return mock_media_session_observer_.get();
-  }
-
   MockAudioFocusDelegate* mock_audio_focus_delegate() {
     return mock_audio_focus_delegate_;
   }
 
   std::unique_ptr<MediaSessionImpl> CreateDummyMediaSession() {
-    return base::WrapUnique<MediaSessionImpl>(new MediaSessionImpl(nullptr));
+    return base::WrapUnique<MediaSessionImpl>(
+        new MediaSessionImpl(CreateBrowser()->web_contents()));
   }
 
   MediaSessionUmaHelper* GetMediaSessionUMAHelper() {
@@ -255,8 +250,6 @@
 
  protected:
   MediaSessionImpl* media_session_;
-  std::unique_ptr<content::MockMediaSessionObserver>
-      mock_media_session_observer_;
   MockAudioFocusDelegate* mock_audio_focus_delegate_;
   std::unique_ptr<content::MockMediaSessionServiceImpl>
       mock_media_session_service_;
@@ -741,14 +734,18 @@
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsShowForContent) {
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false));
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  // Starting a player with a content type should show the media controls.
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    // Starting a player with a persistent type should show the media controls.
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+  }
 
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
@@ -756,14 +753,19 @@
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsNoShowForTransient) {
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, false));
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  // Starting a player with a transient type should not show the media controls.
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    // Starting a player with a transient type should not show the media
+    // controls.
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+  }
 
   EXPECT_FALSE(IsControllable());
   EXPECT_TRUE(IsActive());
@@ -778,12 +780,16 @@
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>(
       shell()->web_contents()->GetMainFrame());
 
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, false));
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
 
-  // Starting a player with a transient type should not show the media controls.
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
-  ResolveAudioFocusSuccess();
+    // Starting a player with a transient type should show the media controls.
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+  }
 
   EXPECT_FALSE(IsControllable());
   EXPECT_TRUE(IsActive());
@@ -795,26 +801,22 @@
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>(
       shell()->web_contents()->GetMainFrame());
 
-  ::testing::Sequence s;
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, false))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, _))
-      .InSequence(s);
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
 
-  // Starting a player with a transient type should not show the media controls.
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
-  ResolveAudioFocusSuccess();
+    // Starting a player with a transient type should not show the media
+    // controls.
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
+    ResolveAudioFocusSuccess();
 
-  SetPlaybackState(blink::mojom::MediaSessionPlaybackState::NONE);
+    SetPlaybackState(blink::mojom::MediaSessionPlaybackState::NONE);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+  }
 
   EXPECT_FALSE(IsControllable());
   EXPECT_TRUE(IsActive());
-
-  // Verify before test exists. Otherwise the sequence will expire and cause
-  // weird problems.
-  ::testing::Mock::VerifyAndClear(mock_media_session_observer());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
@@ -823,26 +825,22 @@
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>(
       shell()->web_contents()->GetMainFrame());
 
-  ::testing::Sequence s;
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, false))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(), MediaSessionStateChanged(true, _))
-      .InSequence(s);
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
 
-  // Starting a player with a transient type should show the media controls if
-  // we have a playback state from the service.
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
-  ResolveAudioFocusSuccess();
+    // Starting a player with a transient type should show the media controls if
+    // we have a playback state from the service.
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
+    ResolveAudioFocusSuccess();
 
-  SetPlaybackState(blink::mojom::MediaSessionPlaybackState::PAUSED);
+    SetPlaybackState(blink::mojom::MediaSessionPlaybackState::PAUSED);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+  }
 
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
-
-  // Verify before test exists. Otherwise the sequence will expire and cause
-  // weird problems.
-  ::testing::Mock::VerifyAndClear(mock_media_session_observer());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
@@ -851,281 +849,463 @@
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>(
       shell()->web_contents()->GetMainFrame());
 
-  ::testing::Sequence s;
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, false))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(), MediaSessionStateChanged(true, _))
-      .InSequence(s);
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
 
-  // Starting a player with a transient type should show the media controls if
-  // we have a playback state from the service.
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
-  ResolveAudioFocusSuccess();
+    // Starting a player with a transient type should show the media controls if
+    // we have a playback state from the service.
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
+    ResolveAudioFocusSuccess();
 
-  SetPlaybackState(blink::mojom::MediaSessionPlaybackState::PLAYING);
+    SetPlaybackState(blink::mojom::MediaSessionPlaybackState::PLAYING);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+  }
 
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
-
-  // Verify before test exists. Otherwise the sequence will expire and cause
-  // weird problems.
-  ::testing::Mock::VerifyAndClear(mock_media_session_observer());
 }
 
 #endif  // !defined(OS_ANDROID)
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsHideWhenStopped) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, true))
-      .After(showControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   RemovePlayers(player_observer.get());
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
+
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_FALSE(IsControllable());
   EXPECT_FALSE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsShownAcceptTransient) {
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false));
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   // Transient player join the session without affecting the controls.
   StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsShownAfterContentAdded) {
-  Expectation dontShowControls = EXPECT_CALL(
-      *mock_media_session_observer(), MediaSessionStateChanged(false, false));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .After(dontShowControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   // The controls are shown when the content player is added.
   StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
   ResolveAudioFocusSuccess();
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsStayIfOnlyOnePlayerHasBeenPaused) {
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false));
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   // Removing only content player doesn't hide the controls since the session
   // is still active.
   RemovePlayer(player_observer.get(), 0);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsHideWhenTheLastPlayerIsRemoved) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, true))
-      .After(showControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+  }
 
   RemovePlayer(player_observer.get(), 0);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
 
   RemovePlayer(player_observer.get(), 1);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+  }
+
   EXPECT_FALSE(IsControllable());
   EXPECT_FALSE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsHideWhenAllThePlayersAreRemoved) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, true))
-      .After(showControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+  }
 
   RemovePlayers(player_observer.get());
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+  }
+
   EXPECT_FALSE(IsControllable());
   EXPECT_FALSE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsNotHideWhenTheLastPlayerIsPaused) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, true))
-      .After(showControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   OnPlayerPaused(player_observer.get(), 0);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
 
   OnPlayerPaused(player_observer.get(), 1);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_FALSE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        SuspendTemporaryUpdatesControls) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, true))
-      .After(showControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   SystemSuspend(true);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_FALSE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsUpdatedWhenResumed) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  Expectation pauseControls = EXPECT_CALL(*mock_media_session_observer(),
-                                          MediaSessionStateChanged(true, true))
-                                  .After(showControls);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .After(pauseControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   SystemSuspend(true);
   SystemResume();
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsHideWhenSessionSuspendedPermanently) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, true))
-      .After(showControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   SystemSuspend(false);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
+
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_FALSE(IsControllable());
   EXPECT_FALSE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsHideWhenSessionStops) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  Expectation pauseControls = EXPECT_CALL(*mock_media_session_observer(),
-                                          MediaSessionStateChanged(true, true))
-                                  .After(showControls);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, true))
-      .After(pauseControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   media_session_->Stop(MediaSession::SuspendType::kUI);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
+
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_FALSE(IsControllable());
   EXPECT_FALSE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsHideWhenSessionChangesFromContentToTransient) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  Expectation pauseControls = EXPECT_CALL(*mock_media_session_observer(),
-                                          MediaSessionStateChanged(true, true))
-                                  .After(showControls);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, false))
-      .After(pauseControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   SystemSuspend(true);
 
-  // This should reset the session and change it to a transient, so
-  // hide the controls.
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    // This should reset the session and change it to a transient, so
+    // hide the controls.
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   EXPECT_FALSE(IsControllable());
   EXPECT_TRUE(IsActive());
@@ -1133,24 +1313,45 @@
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsUpdatedWhenNewPlayerResetsSession) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  Expectation pauseControls = EXPECT_CALL(*mock_media_session_observer(),
-                                          MediaSessionStateChanged(true, true))
-                                  .After(showControls);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .After(pauseControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   SystemSuspend(true);
 
-  // This should reset the session and update the controls.
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    // This should reset the session and update the controls.
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
@@ -1158,24 +1359,45 @@
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsResumedWhenPlayerIsResumed) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  Expectation pauseControls = EXPECT_CALL(*mock_media_session_observer(),
-                                          MediaSessionStateChanged(true, true))
-                                  .After(showControls);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .After(pauseControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   SystemSuspend(true);
 
-  // This should resume the session and update the controls.
-  AddPlayer(player_observer.get(), 0, media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    // This should resume the session and update the controls.
+    AddPlayer(player_observer.get(), 0, media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
@@ -1183,109 +1405,185 @@
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsUpdatedDueToResumeSessionAction) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, true))
-      .After(showControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   UISuspend();
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_FALSE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsUpdatedDueToSuspendSessionAction) {
-  Expectation showControls = EXPECT_CALL(*mock_media_session_observer(),
-                                         MediaSessionStateChanged(true, false));
-  Expectation pauseControls = EXPECT_CALL(*mock_media_session_observer(),
-                                          MediaSessionStateChanged(true, true))
-                                  .After(showControls);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .After(pauseControls);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   UISuspend();
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   UIResume();
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
 
   ResolveAudioFocusSuccess();
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsDontShowWhenOneShotIsPresent) {
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, false));
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::OneShot);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
 
-  EXPECT_FALSE(IsControllable());
-  EXPECT_TRUE(IsActive());
+    StartNewPlayer(player_observer.get(), media::MediaContentType::OneShot);
+    ResolveAudioFocusSuccess();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
-  EXPECT_FALSE(IsControllable());
-  EXPECT_TRUE(IsActive());
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  EXPECT_FALSE(IsControllable());
-  EXPECT_TRUE(IsActive());
+    EXPECT_FALSE(IsControllable());
+    EXPECT_TRUE(IsActive());
+  }
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+
+    EXPECT_FALSE(IsControllable());
+    EXPECT_TRUE(IsActive());
+  }
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+
+    EXPECT_FALSE(IsControllable());
+    EXPECT_TRUE(IsActive());
+  }
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsHiddenAfterRemoveOneShotWithoutOtherPlayers) {
-  Expectation expect_1 = EXPECT_CALL(*mock_media_session_observer(),
-                                     MediaSessionStateChanged(false, false));
-  Expectation expect_2 = EXPECT_CALL(*mock_media_session_observer(),
-                                     MediaSessionStateChanged(false, true))
-                             .After(expect_1);
-  EXPECT_CALL(*mock_media_session_observer(), MediaSessionStateChanged(true, _))
-      .Times(0)
-      .After(expect_2);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::OneShot);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::OneShot);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+  }
+
   RemovePlayer(player_observer.get(), 0);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+  }
+
   EXPECT_FALSE(IsControllable());
   EXPECT_FALSE(IsActive());
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        ControlsShowAfterRemoveOneShotWithPersistentPresent) {
-  Expectation uncontrollable = EXPECT_CALL(
-      *mock_media_session_observer(), MediaSessionStateChanged(false, false));
-
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .After(uncontrollable);
-
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::OneShot);
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::OneShot);
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Transient);
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_FALSE(observer.session_info()->is_controllable);
+  }
 
   RemovePlayer(player_observer.get(), 0);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_TRUE(observer.session_info()->is_controllable);
+  }
+
   EXPECT_TRUE(IsControllable());
   EXPECT_TRUE(IsActive());
 }
@@ -1425,34 +1723,52 @@
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>(
       shell()->web_contents()->GetMainFrame());
 
-  ::testing::Sequence s;
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, true))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, true))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, true))
-      .InSequence(s);
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   OnPlayerPaused(player_observer.get(), 0);
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   SetPlaybackState(blink::mojom::MediaSessionPlaybackState::PLAYING);
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   SetPlaybackState(blink::mojom::MediaSessionPlaybackState::PAUSED);
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   SetPlaybackState(blink::mojom::MediaSessionPlaybackState::NONE);
 
-  // Verify before test exists. Otherwise the sequence will expire and cause
-  // weird problems.
-  ::testing::Mock::VerifyAndClear(mock_media_session_observer());
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
@@ -1460,30 +1776,44 @@
   EnsureMediaSessionService();
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>(
       shell()->web_contents()->GetMainFrame());
-  ::testing::Sequence s;
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .InSequence(s);
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 
   SetPlaybackState(blink::mojom::MediaSessionPlaybackState::PLAYING);
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   SetPlaybackState(blink::mojom::MediaSessionPlaybackState::PAUSED);
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   SetPlaybackState(blink::mojom::MediaSessionPlaybackState::NONE);
 
-  // Verify before test exists. Otherwise the sequence will expire and cause
-  // weird problems.
-  ::testing::Mock::VerifyAndClear(mock_media_session_observer());
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
@@ -1492,25 +1822,52 @@
   auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>(
       shell()->web_contents()->GetMainFrame());
 
-  ::testing::Sequence s;
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false))
-      .InSequence(s);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, _))
-      .InSequence(s);
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
 
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
+    StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
+    ResolveAudioFocusSuccess();
+
+    observer.WaitForState(MediaSessionInfo::SessionState::kActive);
+    EXPECT_EQ(MediaPlaybackState::kPlaying,
+              observer.session_info()->playback_state);
+  }
+
   RemovePlayer(player_observer.get(), 0);
 
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   SetPlaybackState(blink::mojom::MediaSessionPlaybackState::PLAYING);
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   SetPlaybackState(blink::mojom::MediaSessionPlaybackState::PAUSED);
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
+
   SetPlaybackState(blink::mojom::MediaSessionPlaybackState::NONE);
 
-  // Verify before test exists. Otherwise the sequence will expire and cause
-  // weird problems.
-  ::testing::Mock::VerifyAndClear(mock_media_session_observer());
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
+    observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
+    EXPECT_EQ(MediaPlaybackState::kPaused,
+              observer.session_info()->playback_state);
+  }
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
@@ -1818,58 +2175,6 @@
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
                        AddingObserverNotifiesCurrentInformation_EmptyInfo) {
-  media_session_->RemoveObserver(mock_media_session_observer());
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(false, true));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionMetadataChanged(Eq(base::nullopt)));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionActionsChanged(
-                  Eq(std::set<media_session::mojom::MediaSessionAction>())));
-  media_session_->AddObserver(mock_media_session_observer());
-}
-
-IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
-                       AddingObserverNotifiesCurrentInformation_WithInfo) {
-  // Set up the service and information.
-  EnsureMediaSessionService();
-
-  media_session::MediaMetadata metadata;
-  metadata.title = base::ASCIIToUTF16("title");
-  metadata.artist = base::ASCIIToUTF16("artist");
-  metadata.album = base::ASCIIToUTF16("album");
-  mock_media_session_service_->SetMetadata(metadata);
-
-  mock_media_session_service_->EnableAction(
-      media_session::mojom::MediaSessionAction::kSeekForward);
-  std::set<media_session::mojom::MediaSessionAction> expectedActions =
-      mock_media_session_service_->actions();
-
-  // These actions are provided by media session automatically if we are
-  // controllable.
-  expectedActions.insert(media_session::mojom::MediaSessionAction::kPlay);
-  expectedActions.insert(media_session::mojom::MediaSessionAction::kPause);
-  expectedActions.insert(media_session::mojom::MediaSessionAction::kStop);
-
-  // Make sure the service is routed,
-  auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>(
-      shell()->web_contents()->GetMainFrame());
-  StartNewPlayer(player_observer.get(), media::MediaContentType::Persistent);
-  ResolveAudioFocusSuccess();
-
-  // Check if the expectations are met when the observer is newly added.
-  media_session_->RemoveObserver(mock_media_session_observer());
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionStateChanged(true, false));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionMetadataChanged(Eq(metadata)));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionActionsChanged(Eq(expectedActions)));
-  media_session_->AddObserver(mock_media_session_observer());
-}
-
-IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
-                       AddingMojoObserverNotifiesCurrentInformation_EmptyInfo) {
   media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
 
   media_session::MediaMetadata expected_metadata;
@@ -1878,7 +2183,7 @@
 }
 
 IN_PROC_BROWSER_TEST_P(MediaSessionImplParamBrowserTest,
-                       AddingMojoObserverNotifiesCurrentInformation_WithInfo) {
+                       AddingObserverNotifiesCurrentInformation_WithInfo) {
   // Set up the service and information.
   EnsureMediaSessionService();
 
diff --git a/content/browser/media/session/media_session_impl_service_routing_unittest.cc b/content/browser/media/session/media_session_impl_service_routing_unittest.cc
index b03bc6d2..b4c3d73 100644
--- a/content/browser/media/session/media_session_impl_service_routing_unittest.cc
+++ b/content/browser/media/session/media_session_impl_service_routing_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "content/browser/media/session/media_session_player_observer.h"
-#include "content/browser/media/session/mock_media_session_observer.h"
 #include "content/browser/media/session/mock_media_session_service_impl.h"
 #include "content/public/test/test_service_manager_context.h"
 #include "content/test/test_render_view_host.h"
@@ -81,14 +80,12 @@
         std::make_unique<content::TestServiceManagerContext>();
 
     contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
-    mock_media_session_observer_.reset(new NiceMock<MockMediaSessionObserver>(
-        MediaSessionImpl::Get(contents())));
     main_frame_ = contents()->GetMainFrame();
     sub_frame_ = main_frame_->AppendChild("sub_frame");
+    empty_metadata_.source_title = GetExpectedSourceTitle();
   }
 
   void TearDown() override {
-    mock_media_session_observer_.reset();
     services_.clear();
 
     test_service_manager_context_.reset();
@@ -96,10 +93,6 @@
   }
 
  protected:
-  MockMediaSessionObserver* mock_media_session_observer() {
-    return mock_media_session_observer_.get();
-  }
-
   void CreateServiceForFrame(TestRenderFrameHost* frame) {
     services_[frame] =
         std::make_unique<NiceMock<MockMediaSessionServiceImpl>>(frame);
@@ -165,11 +158,13 @@
     return actions_;
   }
 
+  const media_session::MediaMetadata& empty_metadata() const {
+    return empty_metadata_;
+  }
+
   TestRenderFrameHost* main_frame_;
   TestRenderFrameHost* sub_frame_;
 
-  std::unique_ptr<MockMediaSessionObserver> mock_media_session_observer_;
-
   using ServiceMap = std::map<TestRenderFrameHost*,
                               std::unique_ptr<MockMediaSessionServiceImpl>>;
   ServiceMap services_;
@@ -179,6 +174,8 @@
   PlayerMap players_;
 
  private:
+  media_session::MediaMetadata empty_metadata_;
+
   std::set<MediaSessionAction> actions_;
 
   std::unique_ptr<content::TestServiceManagerContext>
@@ -275,48 +272,54 @@
 
 TEST_F(MediaSessionImplServiceRoutingTest,
        DontNotifyMetadataAndActionsChangeWhenUncontrollable) {
-  EXPECT_CALL(*mock_media_session_observer(), MediaSessionMetadataChanged(_))
-      .Times(0);
-  EXPECT_CALL(*mock_media_session_observer(), MediaSessionActionsChanged(_))
-      .Times(0);
+  media_session::test::MockMediaSessionMojoObserver observer(
+      *GetMediaSession());
 
   CreateServiceForFrame(main_frame_);
 
   services_[main_frame_]->SetMetadata(media_session::MediaMetadata());
   services_[main_frame_]->EnableAction(MediaSessionAction::kPlay);
+
+  observer.WaitForActions();
+  EXPECT_TRUE(observer.actions().empty());
+
+  EXPECT_TRUE(observer.WaitForMetadata()->IsEmpty());
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest,
        NotifyMetadataAndActionsChangeWhenControllable) {
-  media_session::MediaMetadata empty_metadata;
-  empty_metadata.source_title = GetExpectedSourceTitle();
-
   media_session::MediaMetadata expected_metadata;
   expected_metadata.title = base::ASCIIToUTF16("title");
   expected_metadata.artist = base::ASCIIToUTF16("artist");
   expected_metadata.album = base::ASCIIToUTF16("album");
   expected_metadata.source_title = GetExpectedSourceTitle();
 
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionMetadataChanged(Eq(empty_metadata)))
-      .Times(AnyNumber());
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionActionsChanged(Eq(default_actions())))
-      .Times(AnyNumber());
-
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionMetadataChanged(Eq(expected_metadata)))
-      .Times(1);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionActionsChanged(Eq(GetDefaultActionsWithExtra(
-                  MediaSessionAction::kSeekForward))))
-      .Times(1);
-
   CreateServiceForFrame(main_frame_);
   StartPlayerForFrame(main_frame_);
 
-  services_[main_frame_]->SetMetadata(expected_metadata);
-  services_[main_frame_]->EnableAction(MediaSessionAction::kSeekForward);
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(
+        *GetMediaSession());
+
+    observer.WaitForActions();
+
+    EXPECT_EQ(default_actions(), observer.actions_set());
+    EXPECT_EQ(empty_metadata(), observer.WaitForNonEmptyMetadata());
+  }
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(
+        *GetMediaSession());
+
+    services_[main_frame_]->SetMetadata(expected_metadata);
+    services_[main_frame_]->EnableAction(MediaSessionAction::kSeekForward);
+
+    observer.WaitForActions();
+
+    EXPECT_EQ(GetDefaultActionsWithExtra(MediaSessionAction::kSeekForward),
+              observer.actions_set());
+    EXPECT_EQ(expected_metadata, observer.WaitForNonEmptyMetadata());
+  }
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest,
@@ -327,20 +330,33 @@
   expected_metadata.album = base::ASCIIToUTF16("album");
   expected_metadata.source_title = GetExpectedSourceTitle();
 
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionMetadataChanged(Eq(expected_metadata)))
-      .Times(1);
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionActionsChanged(Eq(GetDefaultActionsWithExtra(
-                  MediaSessionAction::kSeekForward))))
-      .Times(1);
-
   CreateServiceForFrame(main_frame_);
 
   services_[main_frame_]->SetMetadata(expected_metadata);
   services_[main_frame_]->EnableAction(MediaSessionAction::kSeekForward);
 
-  StartPlayerForFrame(main_frame_);
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(
+        *GetMediaSession());
+
+    observer.WaitForActions();
+
+    EXPECT_TRUE(observer.actions_set().empty());
+    EXPECT_EQ(empty_metadata(), observer.WaitForNonEmptyMetadata());
+  }
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(
+        *GetMediaSession());
+
+    StartPlayerForFrame(main_frame_);
+
+    observer.WaitForActions();
+
+    EXPECT_EQ(GetDefaultActionsWithExtra(MediaSessionAction::kSeekForward),
+              observer.actions_set());
+    EXPECT_EQ(expected_metadata, observer.WaitForNonEmptyMetadata());
+  }
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest,
@@ -351,27 +367,33 @@
   expected_metadata.album = base::ASCIIToUTF16("album");
   expected_metadata.source_title = GetExpectedSourceTitle();
 
-  media_session::MediaMetadata empty_metadata;
-  empty_metadata.source_title = GetExpectedSourceTitle();
-
-  std::set<MediaSessionAction> empty_actions;
-
-  EXPECT_CALL(*mock_media_session_observer(), MediaSessionMetadataChanged(_))
-      .Times(AnyNumber());
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionActionsChanged(default_actions()))
-      .Times(AnyNumber());
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionMetadataChanged(Eq(empty_metadata)));
-  EXPECT_CALL(*mock_media_session_observer(),
-              MediaSessionActionsChanged(Eq(empty_actions)));
-
   CreateServiceForFrame(main_frame_);
 
   services_[main_frame_]->SetMetadata(expected_metadata);
 
   StartPlayerForFrame(main_frame_);
-  ClearPlayersForFrame(main_frame_);
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(
+        *GetMediaSession());
+
+    observer.WaitForActions();
+
+    EXPECT_EQ(default_actions(), observer.actions_set());
+    EXPECT_EQ(expected_metadata, observer.WaitForNonEmptyMetadata());
+  }
+
+  {
+    media_session::test::MockMediaSessionMojoObserver observer(
+        *GetMediaSession());
+
+    ClearPlayersForFrame(main_frame_);
+
+    observer.WaitForActions();
+
+    EXPECT_TRUE(observer.actions_set().empty());
+    EXPECT_EQ(empty_metadata(), observer.WaitForNonEmptyMetadata());
+  }
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest,
@@ -539,7 +561,7 @@
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest,
-       NotifyMojoObserverMetadataWhenControllable) {
+       NotifyObserverMetadataWhenControllable) {
   media_session::MediaMetadata expected_metadata;
   expected_metadata.title = base::ASCIIToUTF16("title");
   expected_metadata.artist = base::ASCIIToUTF16("artist");
@@ -558,7 +580,7 @@
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest,
-       NotifyMojoObserverMetadataEmptyWhenControllable) {
+       NotifyObserverMetadataEmptyWhenControllable) {
   CreateServiceForFrame(main_frame_);
   StartPlayerForFrame(main_frame_);
 
@@ -578,7 +600,7 @@
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest,
-       NotifyMojoObserverWhenTurningUncontrollable) {
+       NotifyObserverWhenTurningUncontrollable) {
   CreateServiceForFrame(main_frame_);
   StartPlayerForFrame(main_frame_);
 
@@ -595,8 +617,7 @@
   }
 }
 
-TEST_F(MediaSessionImplServiceRoutingTest,
-       NotifyMojoObserverWhenActionsChange) {
+TEST_F(MediaSessionImplServiceRoutingTest, NotifyObserverWhenActionsChange) {
   CreateServiceForFrame(main_frame_);
   StartPlayerForFrame(main_frame_);
 
@@ -665,7 +686,7 @@
   }
 }
 
-TEST_F(MediaSessionImplServiceRoutingTest, NotifyMojoObserverOnNavigation) {
+TEST_F(MediaSessionImplServiceRoutingTest, NotifyObserverOnNavigation) {
   media_session::test::MockMediaSessionMojoObserver observer(
       *GetMediaSession());
   contents()->NavigateAndCommit(GURL("http://www.google.com/test"));
@@ -676,7 +697,7 @@
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest,
-       NotifyMojoObserverWithActionsOnAddWhenServiceNotPresent) {
+       NotifyObserverWithActionsOnAddWhenServiceNotPresent) {
   StartPlayerForFrame(main_frame_);
 
   EXPECT_EQ(nullptr, ComputeServiceForRouting());
@@ -689,7 +710,7 @@
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest,
-       NotifyMojoObserverWithActionsOnAddWhenServicePresent) {
+       NotifyObserverWithActionsOnAddWhenServicePresent) {
   CreateServiceForFrame(main_frame_);
   StartPlayerForFrame(main_frame_);
 
@@ -703,7 +724,7 @@
 }
 
 TEST_F(MediaSessionImplServiceRoutingTest,
-       NotifyMojoObserverWithActionsOnAddWhenServiceDestroyed) {
+       NotifyObserverWithActionsOnAddWhenServiceDestroyed) {
   CreateServiceForFrame(main_frame_);
   StartPlayerForFrame(main_frame_);
 
diff --git a/content/browser/media/session/media_session_impl_unittest.cc b/content/browser/media/session/media_session_impl_unittest.cc
index 97596a1..1ced75f4 100644
--- a/content/browser/media/session/media_session_impl_unittest.cc
+++ b/content/browser/media/session/media_session_impl_unittest.cc
@@ -126,6 +126,10 @@
     return media_session::test::GetMediaSessionInfoSync(session)->state;
   }
 
+  void ClearMojoObservers(MediaSessionImpl* session) {
+    session->mojo_observers_.CloseAll();
+  }
+
   bool HasMojoObservers(MediaSessionImpl* session) {
     return !session->mojo_observers_.empty();
   }
@@ -302,6 +306,10 @@
 }
 
 TEST_F(MediaSessionImplTest, RegisterMojoObserver) {
+  // There is no way to get the number of mojo observers so we should just
+  // remove them all and check if the mojo observers interface ptr set is
+  // empty or not.
+  ClearMojoObservers(GetMediaSession());
   EXPECT_FALSE(HasMojoObservers(GetMediaSession()));
 
   MockMediaSessionMojoObserver observer(*GetMediaSession());
diff --git a/content/browser/media/session/mock_media_session_observer.cc b/content/browser/media/session/mock_media_session_observer.cc
deleted file mode 100644
index 471e8485..0000000
--- a/content/browser/media/session/mock_media_session_observer.cc
+++ /dev/null
@@ -1,14 +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 "content/browser/media/session/mock_media_session_observer.h"
-
-namespace content {
-
-MockMediaSessionObserver::MockMediaSessionObserver(MediaSession* media_session)
-    : MediaSessionObserver(media_session) {}
-
-MockMediaSessionObserver::~MockMediaSessionObserver() = default;
-
-}  // content
diff --git a/content/browser/media/session/mock_media_session_observer.h b/content/browser/media/session/mock_media_session_observer.h
deleted file mode 100644
index b025da1..0000000
--- a/content/browser/media/session/mock_media_session_observer.h
+++ /dev/null
@@ -1,31 +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 CONTENT_BROWSER_MEDIA_SESSION_MOCK_MEDIA_SESSION_OBSERVER_H_
-#define CONTENT_BROWSER_MEDIA_SESSION_MOCK_MEDIA_SESSION_OBSERVER_H_
-
-#include "content/public/browser/media_session_observer.h"
-#include "services/media_session/public/cpp/media_metadata.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace content {
-
-class MockMediaSessionObserver : public MediaSessionObserver {
- public:
-  MockMediaSessionObserver(MediaSession* media_session);
-  ~MockMediaSessionObserver() override;
-
-  MOCK_METHOD0(MediaSessionDestroyed, void());
-  MOCK_METHOD2(MediaSessionStateChanged,
-               void(bool is_controllable, bool is_suspended));
-  MOCK_METHOD1(
-      MediaSessionMetadataChanged,
-      void(const base::Optional<media_session::MediaMetadata>& metadata));
-  MOCK_METHOD1(
-      MediaSessionActionsChanged,
-      void(const std::set<media_session::mojom::MediaSessionAction>& action));
-};
-}
-
-#endif  // CONTENT_BROWSER_MEDIA_SESSION_MOCK_MEDIA_SESSION_OBSERVER_H_
diff --git a/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc b/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc
index 9d0183f..3d618bf 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc
+++ b/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc
@@ -67,6 +67,8 @@
       return WebTouchPoint::kStateMoved;
     case SyntheticPointerActionParams::PointerActionType::RELEASE:
       return WebTouchPoint::kStateReleased;
+    case SyntheticPointerActionParams::PointerActionType::CANCEL:
+      return WebTouchPoint::kStateCancelled;
     case SyntheticPointerActionParams::PointerActionType::IDLE:
       return WebTouchPoint::kStateStationary;
     case SyntheticPointerActionParams::PointerActionType::LEAVE:
@@ -90,6 +92,7 @@
       return WebInputEvent::kMouseUp;
     case SyntheticPointerActionParams::PointerActionType::LEAVE:
       return WebInputEvent::kMouseLeave;
+    case SyntheticPointerActionParams::PointerActionType::CANCEL:
     case SyntheticPointerActionParams::PointerActionType::IDLE:
     case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED:
       NOTREACHED()
diff --git a/content/browser/renderer_host/input/synthetic_mouse_driver.cc b/content/browser/renderer_host/input/synthetic_mouse_driver.cc
index 05fb817..31e6b96e 100644
--- a/content/browser/renderer_host/input/synthetic_mouse_driver.cc
+++ b/content/browser/renderer_host/input/synthetic_mouse_driver.cc
@@ -70,6 +70,10 @@
       (~SyntheticPointerActionParams::GetWebMouseEventModifier(button));
 }
 
+void SyntheticMouseDriver::Cancel(int index) {
+  NOTIMPLEMENTED();
+}
+
 void SyntheticMouseDriver::Leave(int index) {
   NOTIMPLEMENTED();
 }
diff --git a/content/browser/renderer_host/input/synthetic_mouse_driver.h b/content/browser/renderer_host/input/synthetic_mouse_driver.h
index aeb408d..594a1d6 100644
--- a/content/browser/renderer_host/input/synthetic_mouse_driver.h
+++ b/content/browser/renderer_host/input/synthetic_mouse_driver.h
@@ -31,6 +31,7 @@
                SyntheticPointerActionParams::Button button =
                    SyntheticPointerActionParams::Button::LEFT,
                int key_modifiers = 0) override;
+  void Cancel(int index = 0) override;
   void Leave(int index = 0) override;
 
   bool UserInputCheck(
diff --git a/content/browser/renderer_host/input/synthetic_pointer_action.cc b/content/browser/renderer_host/input/synthetic_pointer_action.cc
index 00b5580..7e370d5c 100644
--- a/content/browser/renderer_host/input/synthetic_pointer_action.cc
+++ b/content/browser/renderer_host/input/synthetic_pointer_action.cc
@@ -86,6 +86,9 @@
         synthetic_pointer_driver_->Release(param.pointer_id(), param.button(),
                                            param.key_modifiers());
         break;
+      case SyntheticPointerActionParams::PointerActionType::CANCEL:
+        synthetic_pointer_driver_->Cancel(param.pointer_id());
+        break;
       case SyntheticPointerActionParams::PointerActionType::LEAVE:
         synthetic_pointer_driver_->Leave(param.pointer_id());
         break;
diff --git a/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc b/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc
index c62b53b6..326b505f 100644
--- a/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc
+++ b/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc
@@ -30,6 +30,8 @@
       return WebTouchPoint::kStateMoved;
     case SyntheticPointerActionParams::PointerActionType::RELEASE:
       return WebTouchPoint::kStateReleased;
+    case SyntheticPointerActionParams::PointerActionType::CANCEL:
+      return WebTouchPoint::kStateCancelled;
     case SyntheticPointerActionParams::PointerActionType::IDLE:
       return WebTouchPoint::kStateStationary;
     case SyntheticPointerActionParams::PointerActionType::LEAVE:
@@ -53,6 +55,7 @@
       return WebInputEvent::kMouseUp;
     case SyntheticPointerActionParams::PointerActionType::LEAVE:
       return WebInputEvent::kMouseLeave;
+    case SyntheticPointerActionParams::PointerActionType::CANCEL:
     case SyntheticPointerActionParams::PointerActionType::IDLE:
     case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED:
       NOTREACHED()
@@ -508,6 +511,70 @@
   }
 }
 
+TEST_F(SyntheticPointerActionTest, PointerTouchActionCancel) {
+  CreateSyntheticPointerActionTarget<MockSyntheticPointerTouchActionTarget>();
+
+  // Send a touch press for one finger.
+  SyntheticPointerActionParams param1 = SyntheticPointerActionParams(
+      SyntheticPointerActionParams::PointerActionType::PRESS);
+  param1.set_pointer_id(0);
+  param1.set_position(gfx::PointF(54, 89));
+  SyntheticPointerActionListParams::ParamList param_list1;
+  param_list1.push_back(param1);
+  params_.PushPointerActionParamsList(param_list1);
+
+  // Send a touch move for the first finger and a touch press for the second
+  // finger.
+  param1.set_pointer_action_type(
+      SyntheticPointerActionParams::PointerActionType::MOVE);
+  param1.set_position(gfx::PointF(133, 156));
+  SyntheticPointerActionParams param2 = SyntheticPointerActionParams(
+      SyntheticPointerActionParams::PointerActionType::PRESS);
+  param2.set_pointer_id(1);
+  param2.set_position(gfx::PointF(79, 132));
+  SyntheticPointerActionListParams::ParamList param_list2;
+  param_list2.push_back(param1);
+  param_list2.push_back(param2);
+  params_.PushPointerActionParamsList(param_list2);
+
+  // Send touch cancel for both fingers.
+  SyntheticPointerActionListParams::ParamList param_list3;
+  param1.set_pointer_action_type(
+      SyntheticPointerActionParams::PointerActionType::CANCEL);
+  param2.set_pointer_action_type(
+      SyntheticPointerActionParams::PointerActionType::CANCEL);
+  param_list3.push_back(param1);
+  param_list3.push_back(param2);
+  params_.PushPointerActionParamsList(param_list3);
+  pointer_action_.reset(new SyntheticPointerAction(params_));
+
+  ForwardSyntheticPointerAction();
+  MockSyntheticPointerTouchActionTarget* pointer_touch_target =
+      static_cast<MockSyntheticPointerTouchActionTarget*>(target_.get());
+  int index_array[2] = {0, 1};
+  EXPECT_EQ(1, num_success_);
+  EXPECT_EQ(0, num_failure_);
+  EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchStart);
+  EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
+      param_list1, index_array));
+
+  ForwardSyntheticPointerAction();
+  EXPECT_EQ(2, num_success_);
+  EXPECT_EQ(0, num_failure_);
+  // The type of the SyntheticWebTouchEvent is the action of the last finger.
+  EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchStart);
+  EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
+      param_list2, index_array));
+
+  ForwardSyntheticPointerAction();
+  index_array[1] = 0;
+  EXPECT_EQ(3, num_success_);
+  EXPECT_EQ(0, num_failure_);
+  EXPECT_EQ(pointer_touch_target->type(), WebInputEvent::kTouchCancel);
+  EXPECT_TRUE(pointer_touch_target->SyntheticTouchActionListDispatchedCorrectly(
+      param_list3, index_array));
+}
+
 TEST_F(SyntheticPointerActionTest, PointerTouchActionTypeInvalid) {
   CreateSyntheticPointerActionTarget<MockSyntheticPointerTouchActionTarget>();
 
diff --git a/content/browser/renderer_host/input/synthetic_pointer_driver.h b/content/browser/renderer_host/input/synthetic_pointer_driver.h
index abaf51c..75a6392a 100644
--- a/content/browser/renderer_host/input/synthetic_pointer_driver.h
+++ b/content/browser/renderer_host/input/synthetic_pointer_driver.h
@@ -39,6 +39,7 @@
                        SyntheticPointerActionParams::Button button =
                            SyntheticPointerActionParams::Button::LEFT,
                        int key_modifiers = 0) = 0;
+  virtual void Cancel(int index = 0) = 0;
   virtual void Leave(int index = 0) = 0;
 
   // Check if the user inputs in the SyntheticPointerActionParams can generate
diff --git a/content/browser/renderer_host/input/synthetic_touch_driver.cc b/content/browser/renderer_host/input/synthetic_touch_driver.cc
index 40733b5..015acb3 100644
--- a/content/browser/renderer_host/input/synthetic_touch_driver.cc
+++ b/content/browser/renderer_host/input/synthetic_touch_driver.cc
@@ -54,6 +54,14 @@
   pointer_id_map_.erase(index);
 }
 
+void SyntheticTouchDriver::Cancel(int index) {
+  DCHECK_GE(index, 0);
+  DCHECK(pointer_id_map_.find(index) != pointer_id_map_.end());
+  touch_event_.CancelPoint(pointer_id_map_[index]);
+  touch_event_.dispatch_type = blink::WebInputEvent::kEventNonBlocking;
+  pointer_id_map_.erase(index);
+}
+
 void SyntheticTouchDriver::Leave(int index) {
   NOTIMPLEMENTED();
 }
diff --git a/content/browser/renderer_host/input/synthetic_touch_driver.h b/content/browser/renderer_host/input/synthetic_touch_driver.h
index 2aa88c6e..b73d951 100644
--- a/content/browser/renderer_host/input/synthetic_touch_driver.h
+++ b/content/browser/renderer_host/input/synthetic_touch_driver.h
@@ -33,7 +33,8 @@
                SyntheticPointerActionParams::Button button =
                    SyntheticPointerActionParams::Button::LEFT,
                int key_modifiers = 0) override;
-  void Leave(int index) override;
+  void Cancel(int index = 0) override;
+  void Leave(int index = 0) override;
 
   bool UserInputCheck(
       const SyntheticPointerActionParams& params) const override;
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index 74ecab2f..1171031a 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -616,13 +616,14 @@
 
 void VideoCaptureController::OnStarted() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  EmitLogMessage(__func__, 3);
   state_ = blink::VIDEO_CAPTURE_STATE_STARTED;
   PerformForClientsWithOpenSession(base::BindRepeating(&CallOnStarted));
 }
 
 void VideoCaptureController::OnStartedUsingGpuDecode() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  OnLog("StartedUsingGpuDecode");
+  EmitLogMessage(__func__, 3);
   PerformForClientsWithOpenSession(
       base::BindRepeating(&CallOnStartedUsingGpuDecode));
 }
@@ -630,6 +631,7 @@
 void VideoCaptureController::OnDeviceLaunched(
     std::unique_ptr<LaunchedVideoCaptureDevice> device) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  EmitLogMessage(__func__, 3);
   launched_device_ = std::move(device);
   for (auto& entry : buffer_contexts_)
     entry.set_consumer_feedback_observer(launched_device_.get());
@@ -641,6 +643,7 @@
 void VideoCaptureController::OnDeviceLaunchFailed(
     media::VideoCaptureError error) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  EmitLogMessage(__func__, 3);
   if (device_launch_observer_) {
     device_launch_observer_->OnDeviceLaunchFailed(this, error);
     device_launch_observer_ = nullptr;
@@ -649,6 +652,7 @@
 
 void VideoCaptureController::OnDeviceLaunchAborted() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  EmitLogMessage(__func__, 3);
   if (device_launch_observer_) {
     device_launch_observer_->OnDeviceLaunchAborted();
     device_launch_observer_ = nullptr;
@@ -657,6 +661,7 @@
 
 void VideoCaptureController::OnDeviceConnectionLost() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  EmitLogMessage(__func__, 3);
   if (device_launch_observer_) {
     device_launch_observer_->OnDeviceConnectionLost(this);
     device_launch_observer_ = nullptr;
@@ -732,12 +737,14 @@
 void VideoCaptureController::MaybeSuspend() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(launched_device_);
+  EmitLogMessage(__func__, 3);
   launched_device_->MaybeSuspendDevice();
 }
 
 void VideoCaptureController::Resume() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(launched_device_);
+  EmitLogMessage(__func__, 3);
   launched_device_->ResumeDevice();
 }
 
diff --git a/content/browser/renderer_host/media/video_capture_host.cc b/content/browser/renderer_host/media/video_capture_host.cc
index 4030136..23e7ae3 100644
--- a/content/browser/renderer_host/media/video_capture_host.cc
+++ b/content/browser/renderer_host/media/video_capture_host.cc
@@ -319,6 +319,19 @@
   std::move(callback).Run(formats_in_use);
 }
 
+void VideoCaptureHost::OnLog(int32_t device_id, const std::string& message) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  VideoCaptureControllerID controller_id(device_id);
+  auto it = controllers_.find(controller_id);
+  if (it == controllers_.end())
+    return;
+
+  const base::WeakPtr<VideoCaptureController>& controller = it->second;
+  if (controller)
+    controller->OnLog(message);
+}
+
 void VideoCaptureHost::DoError(VideoCaptureControllerID controller_id,
                                media::VideoCaptureError error) {
   DVLOG(1) << __func__;
diff --git a/content/browser/renderer_host/media/video_capture_host.h b/content/browser/renderer_host/media/video_capture_host.h
index afaf18d..7f8871d 100644
--- a/content/browser/renderer_host/media/video_capture_host.h
+++ b/content/browser/renderer_host/media/video_capture_host.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_HOST_H_
 
 #include <map>
+#include <string>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -89,6 +90,7 @@
   void GetDeviceFormatsInUse(int32_t device_id,
                              int32_t session_id,
                              GetDeviceFormatsInUseCallback callback) override;
+  void OnLog(int32_t device_id, const std::string& message) override;
 
   void DoError(VideoCaptureControllerID id, media::VideoCaptureError error);
   void DoEnded(VideoCaptureControllerID id);
diff --git a/content/browser/resources/gpu/browser_bridge.js b/content/browser/resources/gpu/browser_bridge.js
index cf16570..9fc1ec3 100644
--- a/content/browser/resources/gpu/browser_bridge.js
+++ b/content/browser/resources/gpu/browser_bridge.js
@@ -6,34 +6,32 @@
    * This class provides a 'bridge' for communicating between javascript and the
    * browser. When run outside of WebUI, e.g. as a regular webpage, it provides
    * synthetic data to assist in testing.
-   * @constructor
    */
-  function BrowserBridge() {
-    // If we are not running inside WebUI, output chrome.send messages
-    // to the console to help with quick-iteration debugging.
-    this.debugMode_ = (chrome.send === undefined && console.log);
-    if (this.debugMode_) {
-      var browserBridgeTests = document.createElement('script');
-      browserBridgeTests.src = './gpu_internals/browser_bridge_tests.js';
-      document.body.appendChild(browserBridgeTests);
+  class BrowserBridge extends cr.EventTarget {
+    constructor() {
+      super();
+      // If we are not running inside WebUI, output chrome.send messages
+      // to the console to help with quick-iteration debugging.
+      this.debugMode_ = (chrome.send === undefined && console.log);
+      if (this.debugMode_) {
+        var browserBridgeTests = document.createElement('script');
+        browserBridgeTests.src = './gpu_internals/browser_bridge_tests.js';
+        document.body.appendChild(browserBridgeTests);
+      }
+
+      this.nextRequestId_ = 0;
+      this.pendingCallbacks_ = [];
+      this.logMessages_ = [];
+
+      // Tell c++ code that we are ready to receive GPU Info.
+      if (!this.debugMode_) {
+        chrome.send('browserBridgeInitialized');
+        this.beginRequestClientInfo_();
+        this.beginRequestLogMessages_();
+      }
     }
 
-    this.nextRequestId_ = 0;
-    this.pendingCallbacks_ = [];
-    this.logMessages_ = [];
-
-    // Tell c++ code that we are ready to receive GPU Info.
-    if (!this.debugMode_) {
-      chrome.send('browserBridgeInitialized');
-      this.beginRequestClientInfo_();
-      this.beginRequestLogMessages_();
-    }
-  }
-
-  BrowserBridge.prototype = {
-    __proto__: cr.EventTarget.prototype,
-
-    applySimulatedData_: function applySimulatedData(data) {
+    applySimulatedData_(data) {
       // set up things according to the simulated data
       this.gpuInfo_ = data.gpuInfo;
       this.clientInfo_ = data.clientInfo;
@@ -41,7 +39,7 @@
       cr.dispatchSimpleEvent(this, 'gpuInfoUpdate');
       cr.dispatchSimpleEvent(this, 'clientInfoChange');
       cr.dispatchSimpleEvent(this, 'logMessagesChange');
-    },
+    }
 
     /**
      * Returns true if the page is hosted inside Chrome WebUI
@@ -49,13 +47,13 @@
      */
     get debugMode() {
       return this.debugMode_;
-    },
+    }
 
     /**
      * Sends a message to the browser with specified args. The
      * browser will reply asynchronously via the provided callback.
      */
-    callAsync: function(submessage, args, callback) {
+    callAsync(submessage, args, callback) {
       var requestId = this.nextRequestId_;
       this.nextRequestId_ += 1;
       this.pendingCallbacks_[requestId] = callback;
@@ -65,40 +63,40 @@
         var allArgs = [requestId.toString(), submessage].concat(args);
         chrome.send('callAsync', allArgs);
       }
-    },
+    }
 
     /**
      * Called by gpu c++ code when client info is ready.
      */
-    onCallAsyncReply: function(requestId, args) {
+    onCallAsyncReply(requestId, args) {
       if (this.pendingCallbacks_[requestId] === undefined) {
         throw new Error('requestId ' + requestId + ' is not pending');
       }
       var callback = this.pendingCallbacks_[requestId];
       callback(args);
       delete this.pendingCallbacks_[requestId];
-    },
+    }
 
     /**
      * Get gpuInfo data.
      */
     get gpuInfo() {
       return this.gpuInfo_;
-    },
+    }
 
     /**
      * Called from gpu c++ code when GPU Info is updated.
      */
-    onGpuInfoUpdate: function(gpuInfo) {
+    onGpuInfoUpdate(gpuInfo) {
       this.gpuInfo_ = gpuInfo;
       cr.dispatchSimpleEvent(this, 'gpuInfoUpdate');
-    },
+    }
 
     /**
      * This function begins a request for the ClientInfo. If it comes back
      * as undefined, then we will issue the request again in 250ms.
      */
-    beginRequestClientInfo_: function() {
+    beginRequestClientInfo_() {
       this.callAsync(
           'requestClientInfo', undefined,
           (function(data) {
@@ -109,20 +107,20 @@
               cr.dispatchSimpleEvent(this, 'clientInfoChange');
             }
           }).bind(this));
-    },
+    }
 
     /**
      * Returns information about the currently running Chrome build.
      */
     get clientInfo() {
       return this.clientInfo_;
-    },
+    }
 
     /**
      * This function checks for new GPU_LOG messages.
      * If any are found, a refresh is triggered.
      */
-    beginRequestLogMessages_: function() {
+    beginRequestLogMessages_() {
       this.callAsync(
           'requestLogMessages', undefined,
           (function(messages) {
@@ -133,19 +131,19 @@
             // check again in 250 ms
             window.setTimeout(this.beginRequestLogMessages_.bind(this), 250);
           }).bind(this));
-    },
+    }
 
     /**
      * Returns an array of log messages issued by the GPU process, if any.
      */
     get logMessages() {
       return this.logMessages_;
-    },
+    }
 
     /**
      * Returns the value of the "Sandboxed" row.
      */
-    isSandboxedForTesting: function() {
+    isSandboxedForTesting() {
       for (i = 0; i < this.gpuInfo_.basicInfo.length; ++i) {
         var info = this.gpuInfo_.basicInfo[i];
         if (info.description == 'Sandboxed') {
@@ -154,7 +152,7 @@
       }
       return false;
     }
-  };
+  }
 
   return {BrowserBridge: BrowserBridge};
 });
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc
index 2ec604ca..218cd19 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.cc
+++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -31,6 +31,7 @@
 #include "content/public/browser/shared_cors_origin_access_list.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/origin_util.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/network/loader_util.h"
@@ -198,9 +199,10 @@
   }
 
   // Set Fetch metadata headers if necessary.
-  if (base::FeatureList::IsEnabled(features::kSecMetadata) ||
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableExperimentalWebPlatformFeatures)) {
+  if ((base::FeatureList::IsEnabled(features::kSecMetadata) ||
+       base::CommandLine::ForCurrentProcess()->HasSwitch(
+           switches::kEnableExperimentalWebPlatformFeatures)) &&
+      IsOriginSecure(resource_request->url)) {
     // The worker's origin can be different from the constructor's origin, for
     // example, when the worker created from the extension.
     // TODO(hiroshige): Add DCHECK to make sure the same-originness once the
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index f5ccba79..0eeee56b 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -182,7 +182,6 @@
     "media/aec_dump_messages.h",
     "media/cdm_info.cc",
     "media/media_player_delegate_messages.h",
-    "media/media_player_messages_android.h",
     "media/peer_connection_tracker_messages.h",
     "mime_sniffing_throttle.cc",
     "mime_sniffing_throttle.h",
diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h
index 8e2b88d..3fb646b 100644
--- a/content/common/content_message_generator.h
+++ b/content/common/content_message_generator.h
@@ -101,9 +101,4 @@
 #ifndef CONTENT_COMMON_GIN_JAVA_BRIDGE_MESSAGES_H_
 #error "Failed to include content/common/gin_java_bridge_messages.h"
 #endif
-#undef CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ANDROID_H_
-#include "content/common/media/media_player_messages_android.h"
-#ifndef CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ANDROID_H_
-#error "Failed to include content/common/media/media_player_messages_android.h"
-#endif
 #endif  // defined(OS_ANDROID)
diff --git a/content/common/input/actions_parser.cc b/content/common/input/actions_parser.cc
index 39ffd83..27364dcf5 100644
--- a/content/common/input/actions_parser.cc
+++ b/content/common/input/actions_parser.cc
@@ -412,6 +412,7 @@
       action_param.set_button(button);
       action_param.set_key_modifiers(key_modifiers);
       break;
+    case SyntheticPointerActionParams::PointerActionType::CANCEL:
     case SyntheticPointerActionParams::PointerActionType::LEAVE:
     case SyntheticPointerActionParams::PointerActionType::IDLE:
     case SyntheticPointerActionParams::PointerActionType::NOT_INITIALIZED:
diff --git a/content/common/input/synthetic_pointer_action_params.h b/content/common/input/synthetic_pointer_action_params.h
index cea60c9..a11c855 100644
--- a/content/common/input/synthetic_pointer_action_params.h
+++ b/content/common/input/synthetic_pointer_action_params.h
@@ -29,6 +29,7 @@
     PRESS,
     MOVE,
     RELEASE,
+    CANCEL,
     LEAVE,
     IDLE,
     POINTER_ACTION_TYPE_MAX = IDLE
diff --git a/content/common/media/media_player_messages_android.h b/content/common/media/media_player_messages_android.h
deleted file mode 100644
index 24b7fe5..0000000
--- a/content/common/media/media_player_messages_android.h
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ANDROID_H_
-#define CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ANDROID_H_
-
-// IPC messages for android media player.
-
-#include "base/time/time.h"
-#include "content/common/content_export.h"
-#include "ipc/ipc_message_macros.h"
-#include "media/blink/renderer_media_player_interface.h"
-#include "media/gpu/ipc/common/media_param_traits.h"
-#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "url/gurl.h"
-
-#undef IPC_MESSAGE_EXPORT
-#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
-#define IPC_MESSAGE_START MediaPlayerMsgStart
-
-IPC_ENUM_TRAITS_MAX_VALUE(MediaPlayerHostMsg_Initialize_Type,
-                          MEDIA_PLAYER_TYPE_LAST)
-
-IPC_ENUM_TRAITS_MAX_VALUE(blink::WebRemotePlaybackAvailability,
-                          blink::WebRemotePlaybackAvailability::kLast)
-
-// Parameters to describe a media player
-IPC_STRUCT_BEGIN(MediaPlayerHostMsg_Initialize_Params)
-  IPC_STRUCT_MEMBER(MediaPlayerHostMsg_Initialize_Type, type)
-  IPC_STRUCT_MEMBER(int, player_id)
-  IPC_STRUCT_MEMBER(GURL, url)
-  IPC_STRUCT_MEMBER(GURL, site_for_cookies)
-  IPC_STRUCT_MEMBER(GURL, frame_url)
-  IPC_STRUCT_MEMBER(bool, allow_credentials)
-  IPC_STRUCT_MEMBER(int, delegate_id)
-IPC_STRUCT_END()
-
-// Chrome for Android seek message sequence is:
-// 1. Renderer->Browser MediaPlayerHostMsg_Seek
-//    This is the beginning of actual seek flow in response to web app requests
-//    for seeks and browser MediaPlayerMsg_SeekRequests. With this message,
-//    the renderer asks browser to perform actual seek. At most one of these
-//    actual seeks will be in process between this message and renderer's later
-//    receipt of MediaPlayerMsg_SeekCompleted from the browser.
-// 2. Browser->Renderer MediaPlayerMsg_SeekCompleted
-//    Once the browser determines the seek is complete, it sends this message to
-//    notify the renderer of seek completion.
-//
-// Other seek-related IPC messages:
-// Browser->Renderer MediaPlayerMsg_SeekRequest
-//    Browser requests to begin a seek. All browser-initiated seeks must begin
-//    with this request. Renderer controls actual seek initiation via the normal
-//    seek flow, above, keeping web apps aware of seeks. These requests are
-//    also allowed while another actual seek is in progress.
-//
-// Messages for notifying the render process of media playback status -------
-
-// Media buffering has updated.
-IPC_MESSAGE_ROUTED2(MediaPlayerMsg_MediaBufferingUpdate,
-                    int /* player_id */,
-                    int /* percent */)
-
-// A media playback error has occurred.
-IPC_MESSAGE_ROUTED2(MediaPlayerMsg_MediaError,
-                    int /* player_id */,
-                    int /* error */)
-
-// Playback is completed.
-IPC_MESSAGE_ROUTED1(MediaPlayerMsg_MediaPlaybackCompleted,
-                    int /* player_id */)
-
-// Media metadata has changed.
-IPC_MESSAGE_ROUTED5(MediaPlayerMsg_MediaMetadataChanged,
-                    int /* player_id */,
-                    base::TimeDelta /* duration */,
-                    int /* width */,
-                    int /* height */,
-                    bool /* success */)
-
-// Requests renderer player to ask its client (blink HTMLMediaElement) to seek.
-IPC_MESSAGE_ROUTED2(MediaPlayerMsg_SeekRequest,
-                    int /* player_id */,
-                    base::TimeDelta /* time_to_seek_to */)
-
-// Media seek is completed.
-IPC_MESSAGE_ROUTED2(MediaPlayerMsg_SeekCompleted,
-                    int /* player_id */,
-                    base::TimeDelta /* current_time */)
-
-// Video size has changed.
-IPC_MESSAGE_ROUTED3(MediaPlayerMsg_MediaVideoSizeChanged,
-                    int /* player_id */,
-                    int /* width */,
-                    int /* height */)
-
-// The current play time has updated.
-IPC_MESSAGE_ROUTED3(MediaPlayerMsg_MediaTimeUpdate,
-                    int /* player_id */,
-                    base::TimeDelta /* current_timestamp */,
-                    base::TimeTicks /* current_time_ticks */)
-
-// The player has been released.
-IPC_MESSAGE_ROUTED1(MediaPlayerMsg_MediaPlayerReleased,
-                    int /* player_id */)
-
-// The player exited fullscreen.
-IPC_MESSAGE_ROUTED1(MediaPlayerMsg_DidExitFullscreen,
-                    int /* player_id */)
-
-// The player started playing.
-IPC_MESSAGE_ROUTED1(MediaPlayerMsg_DidMediaPlayerPlay,
-                    int /* player_id */)
-
-// The player was paused.
-IPC_MESSAGE_ROUTED1(MediaPlayerMsg_DidMediaPlayerPause,
-                    int /* player_id */)
-
-// Clank has connected to the remote device.
-IPC_MESSAGE_ROUTED2(MediaPlayerMsg_ConnectedToRemoteDevice,
-                    int /* player_id */,
-                    std::string /* remote_playback_message */)
-
-// Clank has disconnected from the remote device.
-IPC_MESSAGE_ROUTED1(MediaPlayerMsg_DisconnectedFromRemoteDevice,
-                    int /* player_id */)
-
-// The remote playback has started.
-IPC_MESSAGE_ROUTED1(MediaPlayerMsg_RemotePlaybackStarted,
-                    int /* player_id */)
-
-// The remote playback device selection has been cancelled.
-IPC_MESSAGE_ROUTED1(MediaPlayerMsg_CancelledRemotePlaybackRequest,
-                    int /* player_id */)
-
-// The availability of remote devices has changed
-IPC_MESSAGE_ROUTED2(MediaPlayerMsg_RemoteRouteAvailabilityChanged,
-                    int /* player_id */,
-                    blink::WebRemotePlaybackAvailability /* availability */)
-
-// Messages for controlling the media playback in browser process ----------
-
-// Destroy the media player object.
-IPC_MESSAGE_ROUTED1(MediaPlayerHostMsg_DestroyMediaPlayer,
-                    int /* player_id */)
-
-// Initialize a media player object.
-IPC_MESSAGE_ROUTED1(
-    MediaPlayerHostMsg_Initialize,
-    MediaPlayerHostMsg_Initialize_Params)
-
-// Pause the player.
-IPC_MESSAGE_ROUTED2(MediaPlayerHostMsg_Pause,
-                    int /* player_id */,
-                    bool /* is_media_related_action */)
-
-// Release player resources after it was suspended.
-IPC_MESSAGE_ROUTED1(MediaPlayerHostMsg_SuspendAndRelease, int /* player_id */)
-
-// Perform a seek.
-IPC_MESSAGE_ROUTED2(MediaPlayerHostMsg_Seek,
-                    int /* player_id */,
-                    base::TimeDelta /* time */)
-
-// Start the player for playback.
-IPC_MESSAGE_ROUTED1(MediaPlayerHostMsg_Start, int /* player_id */)
-
-// Set the volume.
-IPC_MESSAGE_ROUTED2(MediaPlayerHostMsg_SetVolume,
-                    int /* player_id */,
-                    double /* volume */)
-
-// Set the poster image.
-IPC_MESSAGE_ROUTED2(MediaPlayerHostMsg_SetPoster,
-                    int /* player_id */,
-                    GURL /* poster url */)
-
-// Play the media on a remote device, if possible.
-IPC_MESSAGE_ROUTED1(MediaPlayerHostMsg_RequestRemotePlayback,
-                    int /* player_id */)
-
-// Control media playing on a remote device.
-IPC_MESSAGE_ROUTED1(MediaPlayerHostMsg_RequestRemotePlaybackControl,
-                    int /* player_id */)
-
-// Stop playing media on a remote device.
-IPC_MESSAGE_ROUTED1(MediaPlayerHostMsg_RequestRemotePlaybackStop,
-                    int /* player_id */)
-
-#endif  // #ifndef CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ANDROID_H_
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java
index 03aed05c..029e3f2 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java
@@ -55,6 +55,9 @@
     private static final String LONG_VIDEO_SILENT = "long-video-silent";
     private static final int AUDIO_FOCUS_CHANGE_TIMEOUT = 500;  // ms
 
+    // The MediaSessionObserver will always flush the default state first.
+    private static final StateRecord DEFAULT_STATE = new StateRecord(false, true);
+
     private AudioManager getAudioManager() {
         return (AudioManager) mActivityTestRule.getActivity()
                 .getApplicationContext()
@@ -127,6 +130,11 @@
         public int hashCode() {
             return (isControllable ? 2 : 0) + (isSuspended ? 1 : 0);
         }
+
+        @Override
+        public String toString() {
+            return String.format("isControllable=%b isSuspended=%b", isControllable, isSuspended);
+        }
     }
 
     @Before
@@ -491,6 +499,7 @@
     @RetryOnFailure
     public void testSessionSuspendedAfterFocusLossWhenPlaying() throws Exception {
         ArrayList<StateRecord> expectedStates = new ArrayList<StateRecord>();
+        expectedStates.add(DEFAULT_STATE);
         expectedStates.add(new StateRecord(true, false));
         expectedStates.add(new StateRecord(true, true));
 
@@ -521,6 +530,7 @@
     @RetryOnFailure
     public void testSessionSuspendedAfterFocusLossWhenPaused() throws Exception {
         ArrayList<StateRecord> expectedStates = new ArrayList<StateRecord>();
+        expectedStates.add(DEFAULT_STATE);
         expectedStates.add(new StateRecord(true, false));
         expectedStates.add(new StateRecord(true, true));
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index aa6b9f9e..88b4c986 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -211,8 +211,6 @@
     "media/android/media_player_renderer_client.h",
     "media/android/media_player_renderer_client_factory.cc",
     "media/android/media_player_renderer_client_factory.h",
-    "media/android/renderer_media_player_manager.cc",
-    "media/android/renderer_media_player_manager.h",
     "media/android/stream_texture_factory.cc",
     "media/android/stream_texture_factory.h",
     "media/android/stream_texture_wrapper_impl.cc",
@@ -282,7 +280,6 @@
     "media/stream/media_stream_registry_interface.h",
     "media/stream/media_stream_renderer_factory_impl.cc",
     "media/stream/media_stream_renderer_factory_impl.h",
-    "media/stream/media_stream_types.h",
     "media/stream/media_stream_video_capturer_source.cc",
     "media/stream/media_stream_video_capturer_source.h",
     "media/stream/media_stream_video_renderer_sink.cc",
@@ -295,7 +292,6 @@
     "media/stream/processed_local_audio_source.h",
     "media/stream/remote_media_stream_track_adapter.cc",
     "media/stream/remote_media_stream_track_adapter.h",
-    "media/stream/secure_display_link_tracker.h",
     "media/stream/track_audio_renderer.cc",
     "media/stream/track_audio_renderer.h",
     "media/stream/user_media_client_impl.cc",
diff --git a/content/renderer/media/android/renderer_media_player_manager.cc b/content/renderer/media/android/renderer_media_player_manager.cc
deleted file mode 100644
index 933f598..0000000
--- a/content/renderer/media/android/renderer_media_player_manager.cc
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/media/android/renderer_media_player_manager.h"
-
-#include "base/command_line.h"
-#include "content/common/media/media_player_messages_android.h"
-#include "content/renderer/render_view_impl.h"
-#include "media/base/media_switches.h"
-#include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_availability.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace content {
-
-using ::blink::WebRemotePlaybackAvailability;
-
-RendererMediaPlayerManager::RendererMediaPlayerManager(
-    RenderFrame* render_frame)
-    : RenderFrameObserver(render_frame),
-      next_media_player_id_(0) {
-}
-
-RendererMediaPlayerManager::~RendererMediaPlayerManager() {
-  DCHECK(media_players_.empty())
-      << "RendererMediaPlayerManager is owned by RenderFrameImpl and is "
-         "destroyed only after all media players are destroyed.";
-}
-
-bool RendererMediaPlayerManager::OnMessageReceived(const IPC::Message& msg) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(RendererMediaPlayerManager, msg)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaMetadataChanged,
-                        OnMediaMetadataChanged)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaPlaybackCompleted,
-                        OnMediaPlaybackCompleted)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaBufferingUpdate,
-                        OnMediaBufferingUpdate)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_SeekRequest, OnSeekRequest)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_SeekCompleted, OnSeekCompleted)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaError, OnMediaError)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaVideoSizeChanged,
-                        OnVideoSizeChanged)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaTimeUpdate, OnTimeUpdate)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_MediaPlayerReleased,
-                        OnMediaPlayerReleased)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_ConnectedToRemoteDevice,
-                        OnConnectedToRemoteDevice)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DisconnectedFromRemoteDevice,
-                        OnDisconnectedFromRemoteDevice)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_CancelledRemotePlaybackRequest,
-                        OnCancelledRemotePlaybackRequest)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_RemotePlaybackStarted,
-                        OnRemotePlaybackStarted)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidExitFullscreen, OnDidExitFullscreen)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPlay, OnPlayerPlay)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPause, OnPlayerPause)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_RemoteRouteAvailabilityChanged,
-                        OnRemoteRouteAvailabilityChanged)
-  IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void RendererMediaPlayerManager::Initialize(
-    MediaPlayerHostMsg_Initialize_Type type,
-    int player_id,
-    const GURL& url,
-    const GURL& site_for_cookies,
-    const GURL& frame_url,
-    bool allow_credentials,
-    int delegate_id) {
-  MediaPlayerHostMsg_Initialize_Params media_player_params;
-  media_player_params.type = type;
-  media_player_params.player_id = player_id;
-  media_player_params.url = url;
-  media_player_params.site_for_cookies = site_for_cookies;
-  media_player_params.frame_url = frame_url;
-  media_player_params.allow_credentials = allow_credentials;
-  media_player_params.delegate_id = delegate_id;
-
-  Send(new MediaPlayerHostMsg_Initialize(routing_id(), media_player_params));
-}
-
-void RendererMediaPlayerManager::Start(int player_id) {
-  Send(new MediaPlayerHostMsg_Start(routing_id(), player_id));
-}
-
-void RendererMediaPlayerManager::Pause(
-    int player_id,
-    bool is_media_related_action) {
-  Send(new MediaPlayerHostMsg_Pause(
-      routing_id(), player_id, is_media_related_action));
-}
-
-void RendererMediaPlayerManager::Seek(int player_id, base::TimeDelta time) {
-  Send(new MediaPlayerHostMsg_Seek(routing_id(), player_id, time));
-}
-
-void RendererMediaPlayerManager::SetVolume(int player_id, double volume) {
-  Send(new MediaPlayerHostMsg_SetVolume(routing_id(), player_id, volume));
-}
-
-void RendererMediaPlayerManager::SetPoster(int player_id, const GURL& poster) {
-  Send(new MediaPlayerHostMsg_SetPoster(routing_id(), player_id, poster));
-}
-
-void RendererMediaPlayerManager::SuspendAndReleaseResources(int player_id) {
-  Send(new MediaPlayerHostMsg_SuspendAndRelease(routing_id(), player_id));
-}
-
-void RendererMediaPlayerManager::DestroyPlayer(int player_id) {
-  Send(new MediaPlayerHostMsg_DestroyMediaPlayer(routing_id(), player_id));
-}
-
-void RendererMediaPlayerManager::RequestRemotePlayback(int player_id) {
-  Send(new MediaPlayerHostMsg_RequestRemotePlayback(routing_id(), player_id));
-}
-
-void RendererMediaPlayerManager::RequestRemotePlaybackControl(int player_id) {
-  Send(new MediaPlayerHostMsg_RequestRemotePlaybackControl(routing_id(),
-                                                           player_id));
-}
-
-void RendererMediaPlayerManager::RequestRemotePlaybackStop(int player_id) {
-  Send(new MediaPlayerHostMsg_RequestRemotePlaybackStop(routing_id(),
-                                                        player_id));
-}
-
-void RendererMediaPlayerManager::OnMediaMetadataChanged(
-    int player_id,
-    base::TimeDelta duration,
-    int width,
-    int height,
-    bool success) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnMediaMetadataChanged(duration, width, height, success);
-}
-
-void RendererMediaPlayerManager::OnMediaPlaybackCompleted(int player_id) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnPlaybackComplete();
-}
-
-void RendererMediaPlayerManager::OnMediaBufferingUpdate(int player_id,
-                                                        int percent) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnBufferingUpdate(percent);
-}
-
-void RendererMediaPlayerManager::OnSeekRequest(int player_id,
-                                               base::TimeDelta time_to_seek) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnSeekRequest(time_to_seek);
-}
-
-void RendererMediaPlayerManager::OnSeekCompleted(int player_id,
-                                                 base::TimeDelta current_time) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnSeekComplete(current_time);
-}
-
-void RendererMediaPlayerManager::OnMediaError(int player_id, int error) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnMediaError(error);
-}
-
-void RendererMediaPlayerManager::OnVideoSizeChanged(int player_id,
-                                                    int width,
-                                                    int height) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnVideoSizeChanged(width, height);
-}
-
-void RendererMediaPlayerManager::OnTimeUpdate(
-    int player_id,
-    base::TimeDelta current_timestamp,
-    base::TimeTicks current_time_ticks) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnTimeUpdate(current_timestamp, current_time_ticks);
-}
-
-void RendererMediaPlayerManager::OnMediaPlayerReleased(int player_id) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnPlayerReleased();
-}
-
-void RendererMediaPlayerManager::OnConnectedToRemoteDevice(int player_id,
-    const std::string& remote_playback_message) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnConnectedToRemoteDevice(remote_playback_message);
-}
-
-void RendererMediaPlayerManager::OnDisconnectedFromRemoteDevice(int player_id) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnDisconnectedFromRemoteDevice();
-}
-
-void RendererMediaPlayerManager::OnCancelledRemotePlaybackRequest(
-    int player_id) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnCancelledRemotePlaybackRequest();
-}
-
-void RendererMediaPlayerManager::OnRemotePlaybackStarted(
-    int player_id) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnRemotePlaybackStarted();
-}
-
-void RendererMediaPlayerManager::OnDidExitFullscreen(int player_id) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnDidExitFullscreen();
-}
-
-void RendererMediaPlayerManager::OnPlayerPlay(int player_id) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnMediaPlayerPlay();
-}
-
-void RendererMediaPlayerManager::OnPlayerPause(int player_id) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnMediaPlayerPause();
-}
-
-void RendererMediaPlayerManager::OnRemoteRouteAvailabilityChanged(
-    int player_id,
-    blink::WebRemotePlaybackAvailability availability) {
-  media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnRemoteRouteAvailabilityChanged(availability);
-}
-
-int RendererMediaPlayerManager::RegisterMediaPlayer(
-    media::RendererMediaPlayerInterface* player) {
-  media_players_[next_media_player_id_] = player;
-  return next_media_player_id_++;
-}
-
-void RendererMediaPlayerManager::UnregisterMediaPlayer(int player_id) {
-  media_players_.erase(player_id);
-}
-
-media::RendererMediaPlayerInterface* RendererMediaPlayerManager::GetMediaPlayer(
-    int player_id) {
-  std::map<int, media::RendererMediaPlayerInterface*>::iterator iter =
-      media_players_.find(player_id);
-  if (iter != media_players_.end())
-    return iter->second;
-  return NULL;
-}
-
-void RendererMediaPlayerManager::OnDestruct() {
-  delete this;
-}
-
-}  // namespace content
diff --git a/content/renderer/media/android/renderer_media_player_manager.h b/content/renderer/media/android/renderer_media_player_manager.h
deleted file mode 100644
index 08c4116..0000000
--- a/content/renderer/media/android/renderer_media_player_manager.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_MEDIA_ANDROID_RENDERER_MEDIA_PLAYER_MANAGER_H_
-#define CONTENT_RENDERER_MEDIA_ANDROID_RENDERER_MEDIA_PLAYER_MANAGER_H_
-
-#include <map>
-#include <string>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "media/base/android/media_player_android.h"
-#include "media/blink/renderer_media_player_interface.h"
-#include "url/gurl.h"
-
-namespace blink {
-enum class WebRemotePlaybackAvailability;
-}
-
-namespace content {
-class WebMediaPlayerAndroid;
-
-// Class for managing all the WebMediaPlayerAndroid objects in the same
-// RenderFrame.
-class RendererMediaPlayerManager :
-      public RenderFrameObserver,
-      public media::RendererMediaPlayerManagerInterface {
- public:
-  // Constructs a RendererMediaPlayerManager object for the |render_frame|.
-  explicit RendererMediaPlayerManager(RenderFrame* render_frame);
-  ~RendererMediaPlayerManager() override;
-
-  // RenderFrameObserver overrides.
-  bool OnMessageReceived(const IPC::Message& msg) override;
-
-  // Initializes a MediaPlayerAndroid object in browser process.
-  void Initialize(MediaPlayerHostMsg_Initialize_Type type,
-                  int player_id,
-                  const GURL& url,
-                  const GURL& site_for_cookies,
-                  const GURL& frame_url,
-                  bool allow_credentials,
-                  int delegate_id) override;
-
-  // Starts the player.
-  void Start(int player_id) override;
-
-  // Pauses the player.
-  // is_media_related_action should be true if this pause is coming from an
-  // an action that explicitly pauses the video (user pressing pause, JS, etc.)
-  // Otherwise it should be false if Pause is being called due to other reasons
-  // (cleanup, freeing resources, etc.)
-  void Pause(int player_id, bool is_media_related_action) override;
-
-  // Performs seek on the player.
-  void Seek(int player_id, base::TimeDelta time) override;
-
-  // Sets the player volume.
-  void SetVolume(int player_id, double volume) override;
-
-  // Sets the poster image.
-  void SetPoster(int player_id, const GURL& poster) override;
-
-  // Releases resources for the player after being suspended.
-  void SuspendAndReleaseResources(int player_id) override;
-
-  // Destroys the player in the browser process
-  void DestroyPlayer(int player_id) override;
-
-  // Requests remote playback if possible
-  void RequestRemotePlayback(int player_id) override;
-
-  // Requests control of remote playback
-  void RequestRemotePlaybackControl(int player_id) override;
-
-  // Requests stopping remote playback
-  void RequestRemotePlaybackStop(int player_id) override;
-
-  // Registers and unregisters a WebMediaPlayerAndroid object.
-  int RegisterMediaPlayer(media::RendererMediaPlayerInterface* player) override;
-  void UnregisterMediaPlayer(int player_id) override;
-
-  // Gets the pointer to WebMediaPlayerAndroid given the |player_id|.
-  media::RendererMediaPlayerInterface* GetMediaPlayer(int player_id);
-
- private:
-  // RenderFrameObserver implementation.
-  void OnDestruct() override;
-
-  // Message handlers.
-  void OnMediaMetadataChanged(int player_id,
-                              base::TimeDelta duration,
-                              int width,
-                              int height,
-                              bool success);
-  void OnMediaPlaybackCompleted(int player_id);
-  void OnMediaBufferingUpdate(int player_id, int percent);
-  void OnSeekRequest(int player_id, base::TimeDelta time_to_seek);
-  void OnSeekCompleted(int player_id, base::TimeDelta current_timestamp);
-  void OnMediaError(int player_id, int error);
-  void OnVideoSizeChanged(int player_id, int width, int height);
-  void OnTimeUpdate(int player_id,
-                    base::TimeDelta current_timestamp,
-                    base::TimeTicks current_time_ticks);
-  void OnMediaPlayerReleased(int player_id);
-  void OnConnectedToRemoteDevice(int player_id,
-      const std::string& remote_playback_message);
-  void OnDisconnectedFromRemoteDevice(int player_id);
-  void OnCancelledRemotePlaybackRequest(int player_id);
-  void OnRemotePlaybackStarted(int player_id);
-  void OnDidExitFullscreen(int player_id);
-  void OnDidEnterFullscreen(int player_id);
-  void OnPlayerPlay(int player_id);
-  void OnPlayerPause(int player_id);
-  void OnRemoteRouteAvailabilityChanged(
-      int player_id, blink::WebRemotePlaybackAvailability availability);
-
-  // Info for all available WebMediaPlayerAndroid on a page; kept so that
-  // we can enumerate them to send updates about tab focus and visibility.
-  std::map<int, media::RendererMediaPlayerInterface*> media_players_;
-
-  int next_media_player_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(RendererMediaPlayerManager);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MEDIA_ANDROID_RENDERER_MEDIA_PLAYER_MANAGER_H_
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index 81c9877..a4b143c 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -54,7 +54,6 @@
 
 #if defined(OS_ANDROID)
 #include "content/renderer/media/android/media_player_renderer_client_factory.h"
-#include "content/renderer/media/android/renderer_media_player_manager.h"
 #include "content/renderer/media/android/stream_texture_wrapper_impl.h"
 #include "media/base/android/media_codec_util.h"
 #include "media/base/media.h"
@@ -622,14 +621,6 @@
   return decoder_factory_.get();
 }
 
-#if defined(OS_ANDROID)
-RendererMediaPlayerManager* MediaFactory::GetMediaPlayerManager() {
-  if (!media_player_manager_)
-    media_player_manager_ = new RendererMediaPlayerManager(render_frame_);
-  return media_player_manager_;
-}
-#endif  // defined(OS_ANDROID)
-
 #if BUILDFLAG(ENABLE_MEDIA_REMOTING)
 media::mojom::RemoterFactory* MediaFactory::GetRemoterFactory() {
   if (!remoter_factory_) {
diff --git a/content/renderer/media/media_factory.h b/content/renderer/media/media_factory.h
index 7293d2dd..2318074d 100644
--- a/content/renderer/media/media_factory.h
+++ b/content/renderer/media/media_factory.h
@@ -47,9 +47,6 @@
 class RemotePlaybackClientWrapper;
 class RendererWebMediaPlayerDelegate;
 class WebEncryptedMediaClientImpl;
-#if defined(OS_ANDROID)
-class RendererMediaPlayerManager;
-#endif
 }
 
 namespace service_manager {
@@ -65,10 +62,6 @@
 class MediaInterfaceFactory;
 class MediaStreamRendererFactory;
 
-#if defined(OS_ANDROID)
-class RendererMediaPlayerManager;
-#endif
-
 // Assist to RenderFrameImpl in creating various media clients.
 class MediaFactory {
  public:
@@ -149,10 +142,6 @@
 
   media::DecoderFactory* GetDecoderFactory();
 
-#if defined(OS_ANDROID)
-  RendererMediaPlayerManager* GetMediaPlayerManager();
-#endif
-
 #if BUILDFLAG(ENABLE_MEDIA_REMOTING)
   media::mojom::RemoterFactory* GetRemoterFactory();
 #endif
@@ -178,16 +167,6 @@
   // once assigned.
   service_manager::InterfaceProvider* remote_interfaces_ = nullptr;
 
-#if defined(OS_ANDROID)
-  // Manages media players and sessions in this render frame for communicating
-  // with the real media player and sessions in the browser process.
-  // Lifetime is tied to the RenderFrame via the RenderFrameObserver interface.
-  // NOTE: This currently only being used in the case where we are casting. See
-  // also WebMediaPlayerCast (renderer side) and RemoteMediaPlayerManager
-  // (browser side).
-  RendererMediaPlayerManager* media_player_manager_ = nullptr;
-#endif
-
   // Manages play, pause notifications for WebMediaPlayer implementations; its
   // lifetime is tied to the RenderFrame via the RenderFrameObserver interface.
   media::RendererWebMediaPlayerDelegate* media_player_delegate_ = nullptr;
diff --git a/content/renderer/media/stream/media_stream_constraints_util_audio.cc b/content/renderer/media/stream/media_stream_constraints_util_audio.cc
index 2f5aada..3b10468 100644
--- a/content/renderer/media/stream/media_stream_constraints_util_audio.cc
+++ b/content/renderer/media/stream/media_stream_constraints_util_audio.cc
@@ -514,16 +514,14 @@
     }
 
     base::Optional<bool> override_aec3 = GetOverrideAec3();
-    if (override_aec3) {
-      bool use_aec3 = override_aec3.value_or(
-          base::FeatureList::IsEnabled(features::kWebRtcUseEchoCanceller3));
-      if ((use_aec3 && ec_mode_allowed_values_.Contains(
-                           EchoCancellationType::kEchoCancellationAec3)) ||
-          (!use_aec3 && ec_mode_allowed_values_.Contains(
-                            EchoCancellationType::kEchoCancellationAec2))) {
-        return use_aec3 ? EchoCancellationType::kEchoCancellationAec3
-                        : EchoCancellationType::kEchoCancellationAec2;
-      }
+    bool use_aec3 = override_aec3.value_or(
+        base::FeatureList::IsEnabled(features::kWebRtcUseEchoCanceller3));
+    if ((use_aec3 && ec_mode_allowed_values_.Contains(
+                         EchoCancellationType::kEchoCancellationAec3)) ||
+        (!use_aec3 && ec_mode_allowed_values_.Contains(
+                          EchoCancellationType::kEchoCancellationAec2))) {
+      return use_aec3 ? EchoCancellationType::kEchoCancellationAec3
+                      : EchoCancellationType::kEchoCancellationAec2;
     }
 
     // If the previous tie breakers were not enough to determine the selected
diff --git a/content/renderer/media/stream/media_stream_constraints_util_audio_unittest.cc b/content/renderer/media/stream/media_stream_constraints_util_audio_unittest.cc
index 9cecbb3..8a49e26 100644
--- a/content/renderer/media/stream/media_stream_constraints_util_audio_unittest.cc
+++ b/content/renderer/media/stream/media_stream_constraints_util_audio_unittest.cc
@@ -338,7 +338,7 @@
     const auto& properties = result.audio_processing_properties();
     if (IsDeviceCapture()) {
       EXPECT_EQ(properties.echo_cancellation_type,
-                EchoCancellationType::kEchoCancellationAec2);
+                EchoCancellationType::kEchoCancellationAec3);
     } else {
       EXPECT_EQ(properties.echo_cancellation_type,
                 EchoCancellationType::kEchoCancellationDisabled);
@@ -1134,7 +1134,7 @@
       expected_echo_cancellation_type =
           has_system_echo_cancellation
               ? EchoCancellationType::kEchoCancellationSystem
-              : EchoCancellationType::kEchoCancellationAec2;
+              : EchoCancellationType::kEchoCancellationAec3;
     }
     EXPECT_EQ(expected_echo_cancellation_type,
               result.audio_processing_properties().echo_cancellation_type);
@@ -1159,7 +1159,7 @@
       expected_echo_cancellation_type =
           has_system_echo_cancellation
               ? EchoCancellationType::kEchoCancellationSystem
-              : EchoCancellationType::kEchoCancellationAec2;
+              : EchoCancellationType::kEchoCancellationAec3;
     }
     EXPECT_EQ(expected_echo_cancellation_type,
               result.audio_processing_properties().echo_cancellation_type);
@@ -1192,7 +1192,7 @@
         // only the echo_cancellation properties. The other audio processing
         // properties default to false.
         const EchoCancellationType expected_echo_cancellation_type =
-            value ? EchoCancellationType::kEchoCancellationAec2
+            value ? EchoCancellationType::kEchoCancellationAec3
                   : EchoCancellationType::kEchoCancellationDisabled;
         EXPECT_EQ(expected_echo_cancellation_type,
                   properties.echo_cancellation_type);
@@ -1308,7 +1308,7 @@
         // echo_cancellation properties. The other audio processing properties
         // use the default values.
         const EchoCancellationType expected_echo_cancellation_type =
-            value ? EchoCancellationType::kEchoCancellationAec2
+            value ? EchoCancellationType::kEchoCancellationAec3
                   : EchoCancellationType::kEchoCancellationDisabled;
         EXPECT_EQ(expected_echo_cancellation_type,
                   properties.echo_cancellation_type);
@@ -1508,7 +1508,7 @@
           if (ec_value) {
             const EchoCancellationType expected_echo_cancellation_type =
                 ec_type_value == blink::WebString()
-                    ? EchoCancellationType::kEchoCancellationAec2
+                    ? EchoCancellationType::kEchoCancellationAec3
                     : GetEchoCancellationTypeFromConstraintString(
                           ec_type_value);
             EXPECT_EQ(expected_echo_cancellation_type,
diff --git a/content/renderer/media/stream/media_stream_types.h b/content/renderer/media/stream/media_stream_types.h
deleted file mode 100644
index fd6d60cd..0000000
--- a/content/renderer/media/stream/media_stream_types.h
+++ /dev/null
@@ -1,20 +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 CONTENT_RENDERER_MEDIA_STREAM_MEDIA_STREAM_TYPES_H_
-#define CONTENT_RENDERER_MEDIA_STREAM_MEDIA_STREAM_TYPES_H_
-
-#include "media/capture/video_capture_types.h"
-
-namespace content {
-
-using VideoTrackSettingsCallback =
-    base::RepeatingCallback<void(gfx::Size frame_size, double frame_rate)>;
-
-using VideoTrackFormatCallback =
-    base::RepeatingCallback<void(const media::VideoCaptureFormat&)>;
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MEDIA_STREAM_MEDIA_STREAM_TYPES_H_
diff --git a/content/renderer/media/stream/media_stream_video_capturer_source.cc b/content/renderer/media/stream/media_stream_video_capturer_source.cc
index 3dc34f1..9f680bf7 100644
--- a/content/renderer/media/stream/media_stream_video_capturer_source.cc
+++ b/content/renderer/media/stream/media_stream_video_capturer_source.cc
@@ -38,7 +38,7 @@
   explicit LocalVideoCapturerSource(int session_id);
   ~LocalVideoCapturerSource() override;
 
-  // VideoCaptureDelegate Implementation.
+  // VideoCaptureSource Implementation.
   media::VideoCaptureFormats GetPreferredFormats() override;
   void StartCapture(const media::VideoCaptureParams& params,
                     const blink::VideoCaptureDeliverFrameCB& new_frame_callback,
@@ -47,6 +47,7 @@
   void MaybeSuspend() override;
   void Resume() override;
   void StopCapture() override;
+  void OnLog(const std::string& message) override;
 
  private:
   void OnStateUpdate(blink::VideoCaptureState state);
@@ -130,12 +131,22 @@
     base::ResetAndReturn(&stop_capture_cb_).Run();
 }
 
+void LocalVideoCapturerSource::OnLog(const std::string& message) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  manager_->OnLog(session_id_, message);
+}
+
 void LocalVideoCapturerSource::OnStateUpdate(blink::VideoCaptureState state) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (running_callback_.is_null())
+  if (running_callback_.is_null()) {
+    OnLog("LocalVideoCapturerSource::OnStateUpdate discarding state update.");
     return;
+  }
   switch (state) {
     case blink::VIDEO_CAPTURE_STATE_STARTED:
+      OnLog(
+          "LocalVideoCapturerSource::OnStateUpdate signaling to "
+          "consumer that source is now running.");
       running_callback_.Run(true);
       break;
 
@@ -145,6 +156,9 @@
     case blink::VIDEO_CAPTURE_STATE_ENDED:
       release_device_cb_.Run();
       release_device_cb_ = manager_->UseDevice(session_id_);
+      OnLog(
+          "LocalVideoCapturerSource::OnStateUpdate signaling to "
+          "consumer that source is no longer running.");
       running_callback_.Run(false);
       break;
 
@@ -203,6 +217,11 @@
   source_->RequestRefreshFrame();
 }
 
+void MediaStreamVideoCapturerSource::OnLog(const std::string& message) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  source_->OnLog(message);
+}
+
 void MediaStreamVideoCapturerSource::OnHasConsumers(bool has_consumers) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (has_consumers)
@@ -300,6 +319,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   switch (state_) {
     case STARTING:
+      source_->OnLog("MediaStreamVideoCapturerSource sending OnStartDone");
       if (is_running) {
         state_ = STARTED;
         DCHECK(capture_params_ == new_capture_params);
@@ -316,6 +336,8 @@
       }
       break;
     case STOPPING_FOR_RESTART:
+      source_->OnLog(
+          "MediaStreamVideoCapturerSource sending OnStopForRestartDone");
       state_ = is_running ? STARTED : STOPPED;
       OnStopForRestartDone(!is_running);
       break;
@@ -329,6 +351,7 @@
       } else {
         state_ = STOPPED;
       }
+      source_->OnLog("MediaStreamVideoCapturerSource sending OnRestartDone");
       OnRestartDone(is_running);
       break;
     case STOPPED:
diff --git a/content/renderer/media/stream/media_stream_video_capturer_source.h b/content/renderer/media/stream/media_stream_video_capturer_source.h
index 3350c19..6ae378a 100644
--- a/content/renderer/media/stream/media_stream_video_capturer_source.h
+++ b/content/renderer/media/stream/media_stream_video_capturer_source.h
@@ -6,6 +6,7 @@
 #define CONTENT_RENDERER_MEDIA_STREAM_MEDIA_STREAM_VIDEO_CAPTURER_SOURCE_H_
 
 #include <memory>
+#include <string>
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -57,6 +58,7 @@
 
   // MediaStreamVideoSource overrides.
   void RequestRefreshFrame() override;
+  void OnLog(const std::string& message) override;
   void OnHasConsumers(bool has_consumers) override;
   void OnCapturingLinkSecured(bool is_secure) override;
   void StartSourceImpl(
diff --git a/content/renderer/media/stream/media_stream_video_source.cc b/content/renderer/media/stream/media_stream_video_source.cc
index 95bb1758..d0e38bc 100644
--- a/content/renderer/media/stream/media_stream_video_source.cc
+++ b/content/renderer/media/stream/media_stream_video_source.cc
@@ -49,8 +49,8 @@
     MediaStreamVideoTrack* track,
     const VideoTrackAdapterSettings& track_adapter_settings,
     const blink::VideoCaptureDeliverFrameCB& frame_callback,
-    const VideoTrackSettingsCallback& settings_callback,
-    const VideoTrackFormatCallback& format_callback,
+    const blink::VideoTrackSettingsCallback& settings_callback,
+    const blink::VideoTrackFormatCallback& format_callback,
     const ConstraintsCallback& callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!base::ContainsValue(tracks_, track));
@@ -340,11 +340,16 @@
     blink::MediaStreamRequestResult result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(3) << "OnStartDone({result =" << result << "})";
-  if (state_ == ENDED)
+  if (state_ == ENDED) {
+    OnLog(
+        "MediaStreamVideoSource::OnStartDone dropping event because state_ == "
+        "ENDED.");
     return;
+  }
 
   if (result == blink::MEDIA_DEVICE_OK) {
     DCHECK_EQ(STARTING, state_);
+    OnLog("MediaStreamVideoSource changing state to STARTED");
     state_ = STARTED;
     SetReadyState(blink::WebMediaStreamSource::kReadyStateLive);
     StartFrameMonitoring();
@@ -374,8 +379,16 @@
       UpdateTrackSettings(track_info.track, *track_info.adapter_settings);
     }
 
-    if (!track_info.callback.is_null())
+    if (!track_info.callback.is_null()) {
+      OnLog(
+          "MediaStreamVideoSource invoking callback indicating result of "
+          "starting track.");
       track_info.callback.Run(this, result, blink::WebString());
+    } else {
+      OnLog(
+          "MediaStreamVideoSource dropping event indicating result of starting "
+          "track.");
+    }
   }
 }
 
@@ -435,8 +448,8 @@
 MediaStreamVideoSource::PendingTrackInfo::PendingTrackInfo(
     MediaStreamVideoTrack* track,
     const blink::VideoCaptureDeliverFrameCB& frame_callback,
-    const VideoTrackSettingsCallback& settings_callback,
-    const VideoTrackFormatCallback& format_callback,
+    const blink::VideoTrackSettingsCallback& settings_callback,
+    const blink::VideoTrackFormatCallback& format_callback,
     std::unique_ptr<VideoTrackAdapterSettings> adapter_settings,
     const ConstraintsCallback& callback)
     : track(track),
diff --git a/content/renderer/media/stream/media_stream_video_source.h b/content/renderer/media/stream/media_stream_video_source.h
index c05eec85..ec92006 100644
--- a/content/renderer/media/stream/media_stream_video_source.h
+++ b/content/renderer/media/stream/media_stream_video_source.h
@@ -6,6 +6,7 @@
 #define CONTENT_RENDERER_MEDIA_STREAM_MEDIA_STREAM_VIDEO_SOURCE_H_
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/compiler_specific.h"
@@ -14,12 +15,12 @@
 #include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "content/common/content_export.h"
-#include "content/renderer/media/stream/media_stream_types.h"
-#include "content/renderer/media/stream/secure_display_link_tracker.h"
 #include "media/base/video_frame.h"
 #include "media/capture/video_capture_types.h"
 #include "third_party/blink/public/common/media/video_capture.h"
+#include "third_party/blink/public/platform/modules/mediastream/media_stream_types.h"
 #include "third_party/blink/public/platform/modules/mediastream/platform_media_stream_source.h"
+#include "third_party/blink/public/platform/modules/mediastream/secure_display_link_tracker.h"
 #include "third_party/blink/public/platform/web_media_constraints.h"
 #include "third_party/blink/public/platform/web_media_stream_source.h"
 #include "third_party/blink/public/platform/web_media_stream_track.h"
@@ -70,8 +71,8 @@
   void AddTrack(MediaStreamVideoTrack* track,
                 const VideoTrackAdapterSettings& track_adapter_settings,
                 const blink::VideoCaptureDeliverFrameCB& frame_callback,
-                const VideoTrackSettingsCallback& settings_callback,
-                const VideoTrackFormatCallback& format_callback,
+                const blink::VideoTrackSettingsCallback& settings_callback,
+                const blink::VideoTrackFormatCallback& format_callback,
                 const ConstraintsCallback& callback);
   void RemoveTrack(MediaStreamVideoTrack* track, base::OnceClosure callback);
 
@@ -125,6 +126,9 @@
   // Request underlying source to capture a new frame.
   virtual void RequestRefreshFrame() {}
 
+  // Optionally overridden by subclasses to implement handling log messages.
+  virtual void OnLog(const std::string& message) {}
+
   // Enables or disables an heuristic to detect frames from rotated devices.
   void SetDeviceRotationDetection(bool enabled);
 
@@ -273,8 +277,8 @@
     PendingTrackInfo(
         MediaStreamVideoTrack* track,
         const blink::VideoCaptureDeliverFrameCB& frame_callback,
-        const VideoTrackSettingsCallback& settings_callback,
-        const VideoTrackFormatCallback& format_callback,
+        const blink::VideoTrackSettingsCallback& settings_callback,
+        const blink::VideoTrackFormatCallback& format_callback,
         std::unique_ptr<VideoTrackAdapterSettings> adapter_settings,
         const ConstraintsCallback& callback);
     PendingTrackInfo(PendingTrackInfo&& other);
@@ -283,8 +287,8 @@
 
     MediaStreamVideoTrack* track;
     blink::VideoCaptureDeliverFrameCB frame_callback;
-    VideoTrackSettingsCallback settings_callback;
-    VideoTrackFormatCallback format_callback;
+    blink::VideoTrackSettingsCallback settings_callback;
+    blink::VideoTrackFormatCallback format_callback;
     // TODO(guidou): Make |adapter_settings| a regular field instead of a
     // unique_ptr.
     std::unique_ptr<VideoTrackAdapterSettings> adapter_settings;
@@ -308,7 +312,7 @@
   std::vector<MediaStreamVideoTrack*> suspended_tracks_;
 
   // This is used for tracking if all connected video sinks are secure.
-  SecureDisplayLinkTracker<MediaStreamVideoTrack> secure_tracker_;
+  blink::SecureDisplayLinkTracker<MediaStreamVideoTrack> secure_tracker_;
 
   // This flag enables a heuristic to detect device rotation based on frame
   // size.
diff --git a/content/renderer/media/stream/media_stream_video_track.h b/content/renderer/media/stream/media_stream_video_track.h
index 667f787..f3b8eb4 100644
--- a/content/renderer/media/stream/media_stream_video_track.h
+++ b/content/renderer/media/stream/media_stream_video_track.h
@@ -16,7 +16,7 @@
 #include "content/common/content_export.h"
 #include "content/public/renderer/media_stream_video_sink.h"
 #include "content/renderer/media/stream/media_stream_video_source.h"
-#include "content/renderer/media/stream/secure_display_link_tracker.h"
+#include "third_party/blink/public/platform/modules/mediastream/secure_display_link_tracker.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_track.h"
 #include "third_party/blink/public/platform/web_media_stream_track.h"
 
@@ -174,7 +174,7 @@
   base::WeakPtr<MediaStreamVideoSource> source_;
 
   // This is used for tracking if all connected video sinks are secure.
-  SecureDisplayLinkTracker<MediaStreamVideoSink> secure_tracker_;
+  blink::SecureDisplayLinkTracker<MediaStreamVideoSink> secure_tracker_;
 
   // Remembering our desired video size and frame rate.
   int width_ = 0;
diff --git a/content/renderer/media/stream/user_media_client_impl_unittest.cc b/content/renderer/media/stream/user_media_client_impl_unittest.cc
index 806c8cb..f1b803b 100644
--- a/content/renderer/media/stream/user_media_client_impl_unittest.cc
+++ b/content/renderer/media/stream/user_media_client_impl_unittest.cc
@@ -899,7 +899,7 @@
 
   const AudioProcessingProperties& properties =
       audio_capture_settings.audio_processing_properties();
-  EXPECT_EQ(EchoCancellationType::kEchoCancellationAec2,
+  EXPECT_EQ(EchoCancellationType::kEchoCancellationAec3,
             properties.echo_cancellation_type);
   EXPECT_FALSE(properties.goog_audio_mirroring);
   EXPECT_TRUE(properties.goog_auto_gain_control);
diff --git a/content/renderer/media/stream/video_track_adapter.cc b/content/renderer/media/stream/video_track_adapter.cc
index 27d930c..22d2295 100644
--- a/content/renderer/media/stream/video_track_adapter.cc
+++ b/content/renderer/media/stream/video_track_adapter.cc
@@ -123,8 +123,8 @@
  public:
   struct VideoTrackCallbacks {
     blink::VideoCaptureDeliverFrameCB frame_callback;
-    VideoTrackSettingsCallback settings_callback;
-    VideoTrackFormatCallback format_callback;
+    blink::VideoTrackSettingsCallback settings_callback;
+    blink::VideoTrackFormatCallback format_callback;
   };
   // Setting |max_frame_rate| to 0.0, means that no frame rate limitation
   // will be done.
@@ -137,8 +137,8 @@
   // |frame_callback| will however be released on the main render thread.
   void AddCallbacks(const MediaStreamVideoTrack* track,
                     blink::VideoCaptureDeliverFrameCB frame_callback,
-                    VideoTrackSettingsCallback settings_callback,
-                    VideoTrackFormatCallback format_callback);
+                    blink::VideoTrackSettingsCallback settings_callback,
+                    blink::VideoTrackFormatCallback format_callback);
 
   // Removes the callbacks associated with |track| if |track| has been added. It
   // is ok to call RemoveCallbacks() even if |track| has not been added.
@@ -177,7 +177,7 @@
   // Updates track settings if either frame width, height or frame rate have
   // changed since last update.
   void MaybeUpdateTrackSettings(
-      const VideoTrackSettingsCallback& settings_callback,
+      const blink::VideoTrackSettingsCallback& settings_callback,
       const scoped_refptr<media::VideoFrame>& frame);
 
   // Updates computed source format for all tracks if either frame width, height
@@ -240,8 +240,8 @@
 void VideoTrackAdapter::VideoFrameResolutionAdapter::AddCallbacks(
     const MediaStreamVideoTrack* track,
     blink::VideoCaptureDeliverFrameCB frame_callback,
-    VideoTrackSettingsCallback settings_callback,
-    VideoTrackFormatCallback format_callback) {
+    blink::VideoTrackSettingsCallback settings_callback,
+    blink::VideoTrackFormatCallback format_callback) {
   DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   callbacks_.insert({track,
                      {std::move(frame_callback), std::move(settings_callback),
@@ -408,7 +408,7 @@
 }
 
 void VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeUpdateTrackSettings(
-    const VideoTrackSettingsCallback& settings_callback,
+    const blink::VideoTrackSettingsCallback& settings_callback,
     const scoped_refptr<media::VideoFrame>& frame) {
   DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   ComputeFrameRate(frame->timestamp(), &track_settings_.frame_rate,
@@ -502,8 +502,8 @@
 void VideoTrackAdapter::AddTrack(
     const MediaStreamVideoTrack* track,
     blink::VideoCaptureDeliverFrameCB frame_callback,
-    VideoTrackSettingsCallback settings_callback,
-    VideoTrackFormatCallback format_callback,
+    blink::VideoTrackSettingsCallback settings_callback,
+    blink::VideoTrackFormatCallback format_callback,
     const VideoTrackAdapterSettings& settings) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
@@ -517,8 +517,8 @@
 void VideoTrackAdapter::AddTrackOnIO(
     const MediaStreamVideoTrack* track,
     blink::VideoCaptureDeliverFrameCB frame_callback,
-    VideoTrackSettingsCallback settings_callback,
-    VideoTrackFormatCallback format_callback,
+    blink::VideoTrackSettingsCallback settings_callback,
+    blink::VideoTrackFormatCallback format_callback,
     const VideoTrackAdapterSettings& settings) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   scoped_refptr<VideoFrameResolutionAdapter> adapter;
diff --git a/content/renderer/media/stream/video_track_adapter.h b/content/renderer/media/stream/video_track_adapter.h
index 839abcc..4ed082d 100644
--- a/content/renderer/media/stream/video_track_adapter.h
+++ b/content/renderer/media/stream/video_track_adapter.h
@@ -14,9 +14,9 @@
 #include "base/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
-#include "content/renderer/media/stream/media_stream_types.h"
 #include "content/renderer/media/stream/media_stream_video_track.h"
 #include "media/base/video_frame.h"
+#include "third_party/blink/public/platform/modules/mediastream/media_stream_types.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace content {
@@ -92,8 +92,8 @@
   // passing frames and inform of the result via |on_muted_state_callback|.
   void AddTrack(const MediaStreamVideoTrack* track,
                 blink::VideoCaptureDeliverFrameCB frame_callback,
-                VideoTrackSettingsCallback settings_callback,
-                VideoTrackFormatCallback track_callback,
+                blink::VideoTrackSettingsCallback settings_callback,
+                blink::VideoTrackFormatCallback track_callback,
                 const VideoTrackAdapterSettings& settings);
   void RemoveTrack(const MediaStreamVideoTrack* track);
   void ReconfigureTrack(const MediaStreamVideoTrack* track,
@@ -134,8 +134,8 @@
 
   void AddTrackOnIO(const MediaStreamVideoTrack* track,
                     blink::VideoCaptureDeliverFrameCB frame_callback,
-                    VideoTrackSettingsCallback settings_callback,
-                    VideoTrackFormatCallback track_callback,
+                    blink::VideoTrackSettingsCallback settings_callback,
+                    blink::VideoTrackFormatCallback track_callback,
                     const VideoTrackAdapterSettings& settings);
   void RemoveTrackOnIO(const MediaStreamVideoTrack* track);
   void ReconfigureTrackOnIO(const MediaStreamVideoTrack* track,
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index afc9190..44db219 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -173,6 +173,8 @@
     const blink::VideoCaptureDeliverFrameCB& deliver_frame_cb) {
   DVLOG(1) << __func__ << " |device_id_| = " << device_id_;
   DCHECK(io_thread_checker_.CalledOnValidThread());
+  OnLog("VideoCaptureImpl got request to start capture.");
+
   ClientInfo client_info;
   client_info.params = params;
   client_info.state_update_cb = state_update_cb;
@@ -182,6 +184,7 @@
     case blink::VIDEO_CAPTURE_STATE_STARTING:
     case blink::VIDEO_CAPTURE_STATE_STARTED:
       clients_[client_id] = client_info;
+      OnLog("VideoCaptureImpl capture is already started or starting.");
       // TODO(sheu): Allowing resolution change will require that all
       // outstanding clients of a capture session support resolution change.
       DCHECK_EQ(params_.resolution_change_policy,
@@ -202,9 +205,11 @@
 
       DVLOG(1) << "StartCapture: starting with first resolution "
                << params_.requested_format.frame_size.ToString();
+      OnLog("VideoCaptureImpl starting capture.");
       StartCaptureInternal();
       return;
     case blink::VIDEO_CAPTURE_STATE_ERROR:
+      OnLog("VideoCaptureImpl is in error state.");
       state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_ERROR);
       return;
     case blink::VIDEO_CAPTURE_STATE_PAUSED:
@@ -256,12 +261,17 @@
                      weak_factory_.GetWeakPtr(), callback));
 }
 
+void VideoCaptureImpl::OnLog(const std::string& message) {
+  GetVideoCaptureHost()->OnLog(device_id_, message);
+}
+
 void VideoCaptureImpl::OnStateChanged(media::mojom::VideoCaptureState state) {
   DVLOG(1) << __func__ << " state: " << state;
   DCHECK(io_thread_checker_.CalledOnValidThread());
 
   switch (state) {
     case media::mojom::VideoCaptureState::STARTED:
+      OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_STARTED");
       state_ = blink::VIDEO_CAPTURE_STATE_STARTED;
       for (const auto& client : clients_)
         client.second.state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_STARTED);
@@ -271,11 +281,14 @@
       RequestRefreshFrame();
       break;
     case media::mojom::VideoCaptureState::STOPPED:
+      OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_STOPPED");
       state_ = blink::VIDEO_CAPTURE_STATE_STOPPED;
       client_buffers_.clear();
       weak_factory_.InvalidateWeakPtrs();
-      if (!clients_.empty() || !clients_pending_on_restart_.empty())
+      if (!clients_.empty() || !clients_pending_on_restart_.empty()) {
+        OnLog("VideoCaptureImpl restarting capture");
         RestartCapture();
+      }
       break;
     case media::mojom::VideoCaptureState::PAUSED:
       for (const auto& client : clients_)
@@ -286,12 +299,14 @@
         client.second.state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_RESUMED);
       break;
     case media::mojom::VideoCaptureState::FAILED:
+      OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_ERROR");
       for (const auto& client : clients_)
         client.second.state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_ERROR);
       clients_.clear();
       state_ = blink::VIDEO_CAPTURE_STATE_ERROR;
       break;
     case media::mojom::VideoCaptureState::ENDED:
+      OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_ENDED");
       // We'll only notify the client that the stream has stopped.
       for (const auto& client : clients_)
         client.second.state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_STOPPED);
@@ -333,8 +348,10 @@
       media::VideoFrameMetadata::REFERENCE_TIME, &reference_time);
   DCHECK(success);
 
-  if (first_frame_ref_time_.is_null())
+  if (first_frame_ref_time_.is_null()) {
     first_frame_ref_time_ = reference_time;
+    OnLog("First frame received at VideoCaptureImpl");
+  }
 
   // If the timestamp is not prepared, we use reference time to make a rough
   // estimate. e.g. ThreadSafeCaptureOracle::DidCaptureFrame().
@@ -479,6 +496,7 @@
       state_ != blink::VIDEO_CAPTURE_STATE_STARTED)
     return;
   state_ = blink::VIDEO_CAPTURE_STATE_STOPPING;
+  OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_STOPPING");
   GetVideoCaptureHost()->Stop(device_id_);
   params_.requested_format.frame_size.SetSize(0, 0);
 }
@@ -506,6 +524,7 @@
 void VideoCaptureImpl::StartCaptureInternal() {
   DCHECK(io_thread_checker_.CalledOnValidThread());
   state_ = blink::VIDEO_CAPTURE_STATE_STARTING;
+  OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_STARTING");
 
   media::mojom::VideoCaptureObserverPtr observer;
   observer_binding_.Bind(mojo::MakeRequest(&observer));
diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h
index 0fda362..fbef75ba 100644
--- a/content/renderer/media/video_capture_impl.h
+++ b/content/renderer/media/video_capture_impl.h
@@ -9,6 +9,7 @@
 
 #include <list>
 #include <map>
+#include <string>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -63,6 +64,8 @@
   void GetDeviceFormatsInUse(
       const blink::VideoCaptureDeviceFormatsCB& callback);
 
+  void OnLog(const std::string& message);
+
   media::VideoCaptureSessionId session_id() const { return session_id_; }
 
   void SetVideoCaptureHostForTesting(media::mojom::VideoCaptureHost* service) {
diff --git a/content/renderer/media/video_capture_impl_manager.cc b/content/renderer/media/video_capture_impl_manager.cc
index 4f426d5..3edbc14 100644
--- a/content/renderer/media/video_capture_impl_manager.cc
+++ b/content/renderer/media/video_capture_impl_manager.cc
@@ -25,6 +25,7 @@
 #include "content/renderer/media/video_capture_impl_manager.h"
 
 #include <algorithm>
+#include <string>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -118,6 +119,8 @@
   // This ID is used to identify a client of VideoCaptureImpl.
   const int client_id = ++next_client_id_;
 
+  // Use of base::Unretained() is safe because |devices_| is released on the
+  // |io_task_runner()| as well.
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::StartCapture,
                                 base::Unretained(it->impl.get()), client_id,
@@ -133,6 +136,8 @@
       devices_.begin(), devices_.end(),
       [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
+  // Use of base::Unretained() is safe because |devices_| is released on the
+  // |io_task_runner()| as well.
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::RequestRefreshFrame,
                                 base::Unretained(it->impl.get())));
@@ -151,6 +156,8 @@
   it->is_individually_suspended = true;
   if (is_suspending_all_)
     return;  // Device should already be suspended.
+  // Use of base::Unretained() is safe because |devices_| is released on the
+  // |io_task_runner()| as well.
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::SuspendCapture,
                                 base::Unretained(it->impl.get()), true));
@@ -167,6 +174,8 @@
   it->is_individually_suspended = false;
   if (is_suspending_all_)
     return;  // Device must remain suspended until all are resumed.
+  // Use of base::Unretained() is safe because |devices_| is released on the
+  // |io_task_runner()| as well.
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::SuspendCapture,
                                 base::Unretained(it->impl.get()), false));
@@ -180,6 +189,8 @@
       devices_.begin(), devices_.end(),
       [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
+  // Use of base::Unretained() is safe because |devices_| is released on the
+  // |io_task_runner()| as well.
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::GetDeviceSupportedFormats,
                                 base::Unretained(it->impl.get()), callback));
@@ -193,6 +204,8 @@
       devices_.begin(), devices_.end(),
       [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
+  // Use of base::Unretained() is safe because |devices_| is released on the
+  // |io_task_runner()| as well.
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::GetDeviceFormatsInUse,
                                 base::Unretained(it->impl.get()), callback));
@@ -211,6 +224,8 @@
       devices_.begin(), devices_.end(),
       [id] (const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
+  // Use of base::Unretained() is safe because |devices_| is released on the
+  // |io_task_runner()| as well.
   ChildProcess::current()->io_task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::StopCapture,
                                 base::Unretained(it->impl.get()), client_id));
@@ -247,10 +262,26 @@
     DCHECK(it != devices_.end());
     if (it->is_individually_suspended)
       continue;  // Either: 1) Already suspended; or 2) Should not be resumed.
+    // Use of base::Unretained() is safe because |devices_| is released on the
+    // |io_task_runner()| as well.
     ChildProcess::current()->io_task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&VideoCaptureImpl::SuspendCapture,
                                   base::Unretained(it->impl.get()), suspend));
   }
 }
 
+void VideoCaptureImplManager::OnLog(media::VideoCaptureSessionId id,
+                                    const std::string& message) {
+  DCHECK(render_main_task_runner_->BelongsToCurrentThread());
+  const auto it = std::find_if(
+      devices_.begin(), devices_.end(),
+      [id](const DeviceEntry& entry) { return entry.session_id == id; });
+  DCHECK(it != devices_.end());
+  // Use of base::Unretained() is safe because |devices_| is released on the
+  // |io_task_runner()| as well.
+  ChildProcess::current()->io_task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&VideoCaptureImpl::OnLog,
+                                base::Unretained(it->impl.get()), message));
+}
+
 }  // namespace content
diff --git a/content/renderer/media/video_capture_impl_manager.h b/content/renderer/media/video_capture_impl_manager.h
index 27e3c83..68d57dd0 100644
--- a/content/renderer/media/video_capture_impl_manager.h
+++ b/content/renderer/media/video_capture_impl_manager.h
@@ -6,6 +6,7 @@
 #define CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_IMPL_MANAGER_H_
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/callback.h"
@@ -102,6 +103,8 @@
   void SuspendDevices(const blink::MediaStreamDevices& video_devices,
                       bool suspend);
 
+  void OnLog(media::VideoCaptureSessionId id, const std::string& message);
+
   virtual std::unique_ptr<VideoCaptureImpl> CreateVideoCaptureImplForTesting(
       media::VideoCaptureSessionId session_id) const;
 
diff --git a/content/renderer/media/video_capture_impl_manager_unittest.cc b/content/renderer/media/video_capture_impl_manager_unittest.cc
index f901ab7..964b929 100644
--- a/content/renderer/media/video_capture_impl_manager_unittest.cc
+++ b/content/renderer/media/video_capture_impl_manager_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <array>
+#include <string>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -95,6 +96,8 @@
     NOTREACHED();
   }
 
+  MOCK_METHOD2(OnLog, void(int32_t, const std::string&));
+
   PauseResumeCallback* const pause_callback_;
   const base::Closure destruct_callback_;
 
diff --git a/content/renderer/media/video_capture_impl_unittest.cc b/content/renderer/media/video_capture_impl_unittest.cc
index b47ce9c..a3cd2ef 100644
--- a/content/renderer/media/video_capture_impl_unittest.cc
+++ b/content/renderer/media/video_capture_impl_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <stddef.h>
+#include <string>
 
 #include "base/bind.h"
 #include "base/macros.h"
@@ -68,6 +69,7 @@
                void(int32_t, int32_t, GetDeviceSupportedFormatsCallback&));
   MOCK_METHOD3(GetDeviceFormatsInUseMock,
                void(int32_t, int32_t, GetDeviceFormatsInUseCallback&));
+  MOCK_METHOD2(OnLog, void(int32_t, const std::string&));
 
   void GetDeviceSupportedFormats(
       int32_t arg1,
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 0db4d7c..f4ed0b0 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -2029,14 +2029,6 @@
   GetWidget()->PageScaleFactorChanged(webview()->PageScaleFactor());
 }
 
-double RenderViewImpl::zoomLevelToZoomFactor(double zoom_level) const {
-  return ZoomLevelToZoomFactor(zoom_level);
-}
-
-double RenderViewImpl::zoomFactorToZoomLevel(double factor) const {
-  return ZoomFactorToZoomLevel(factor);
-}
-
 void RenderViewImpl::PageImportanceSignalsChanged() {
   if (!webview() || !main_render_frame_)
     return;
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index e2e5e05..4d12866 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -252,8 +252,6 @@
   int HistoryForwardListCount() override;
   void ZoomLimitsChanged(double minimum_level, double maximum_level) override;
   void PageScaleFactorChanged() override;
-  virtual double zoomLevelToZoomFactor(double zoom_level) const;
-  virtual double zoomFactorToZoomLevel(double factor) const;
   void PageImportanceSignalsChanged() override;
   void DidAutoResize(const blink::WebSize& newSize) override;
   blink::WebRect RootWindowRect() override;
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index f75bf59..3013a52 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -719,7 +719,7 @@
   VisualProperties params = original_params;
   // Web tests can override the device scale factor in the renderer.
   if (device_scale_factor_for_testing_) {
-    params.screen_info.device_scale_factor = *device_scale_factor_for_testing_;
+    params.screen_info.device_scale_factor = device_scale_factor_for_testing_;
     params.compositor_viewport_pixel_size = gfx::ScaleToCeiledSize(
         params.new_size, params.screen_info.device_scale_factor);
   }
@@ -1484,20 +1484,15 @@
 
   if (!params.auto_resize_enabled) {
     visible_viewport_size_ = params.visible_viewport_size;
-
     display_mode_ = params.display_mode;
-
     size_ = params.new_size;
 
     ResizeWebWidget();
 
-    WebSize visual_viewport_size;
+    gfx::Size visual_viewport_size = visible_viewport_size_;
     if (compositor_deps_->IsUseZoomForDSFEnabled()) {
-      visual_viewport_size =
-          gfx::ScaleToCeiledSize(params.visible_viewport_size,
-                                 GetOriginalScreenInfo().device_scale_factor);
-    } else {
-      visual_viewport_size = visible_viewport_size_;
+      visual_viewport_size = gfx::ScaleToCeiledSize(
+          visual_viewport_size, GetOriginalScreenInfo().device_scale_factor);
     }
     GetWebWidget()->ResizeVisualViewport(visual_viewport_size);
 
@@ -3333,29 +3328,39 @@
 }
 
 void RenderWidget::SetDeviceScaleFactorForTesting(float factor) {
-  device_scale_factor_for_testing_ = factor;
+  DCHECK_GT(factor, 0.f);
 
-  VisualProperties visual_properties;
-  visual_properties.screen_info = screen_info_;
-  visual_properties.screen_info.device_scale_factor = factor;
-  visual_properties.new_size = size();
-  visual_properties.visible_viewport_size = visible_viewport_size_;
-  visual_properties.compositor_viewport_pixel_size =
-      gfx::ScaleToCeiledSize(size(), factor);
-  visual_properties.browser_controls_shrink_blink_size = false;
-  visual_properties.top_controls_height = 0.f;
-  visual_properties.is_fullscreen_granted = is_fullscreen_granted_;
-  visual_properties.display_mode = display_mode_;
-  visual_properties.local_surface_id_allocation =
-      local_surface_id_allocation_from_parent_;
   // We are changing the device scale factor from the renderer, so allocate a
   // new viz::LocalSurfaceId to avoid surface invariants violations in tests.
   layer_tree_view_->RequestNewLocalSurfaceId();
-  OnSynchronizeVisualProperties(visual_properties);
+
+  ScreenInfo info = screen_info_;
+  info.device_scale_factor = factor;
+  gfx::Size viewport_pixel_size = gfx::ScaleToCeiledSize(size_, factor);
+  UpdateSurfaceAndScreenInfo(local_surface_id_allocation_from_parent_,
+                             viewport_pixel_size, info);
+
+  ResizeWebWidget();  // This picks up the new device scale factor in |info|.
+
+  gfx::Size visible_viewport_size = visible_viewport_size_;
+  if (compositor_deps_->IsUseZoomForDSFEnabled()) {
+    visible_viewport_size =
+        gfx::ScaleToCeiledSize(visible_viewport_size, factor);
+  }
+  GetWebWidget()->ResizeVisualViewport(visible_viewport_size);
+
+  // Make sure the DSF override stays for future VisualProperties updates, and
+  // that includes overriding the VisualProperties'
+  // compositor_viewport_pixel_size with size * this for-testing DSF.
+  device_scale_factor_for_testing_ = factor;
 }
 
 void RenderWidget::SetDeviceColorSpaceForTesting(
     const gfx::ColorSpace& color_space) {
+  // We are changing the device color space from the renderer, so allocate a
+  // new viz::LocalSurfaceId to avoid surface invariants violations in tests.
+  layer_tree_view_->RequestNewLocalSurfaceId();
+
   ScreenInfo info = screen_info_;
   info.color_space = color_space;
   UpdateSurfaceAndScreenInfo(local_surface_id_allocation_from_parent_,
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index a4fc4a0..21145d23d 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -827,7 +827,10 @@
   // The rect where this view should be initially shown.
   gfx::Rect initial_rect_;
 
-  base::Optional<float> device_scale_factor_for_testing_;
+  // Web tests override the device scale factor in the renderer with this. We
+  // store it to keep the override if the browser passes along VisualProperties
+  // with the real device scale factor. A value of 0.f means this is ignored.
+  float device_scale_factor_for_testing_ = 0.f;
 
   // The size of the RenderWidget in DIPs. This may differ from
   // |compositor_viewport_pixel_size_| in the following (and possibly other)
diff --git a/content/shell/browser/shell_platform_data_aura.cc b/content/shell/browser/shell_platform_data_aura.cc
index 6672d886..d89c2f3 100644
--- a/content/shell/browser/shell_platform_data_aura.cc
+++ b/content/shell/browser/shell_platform_data_aura.cc
@@ -23,10 +23,7 @@
 #include "ui/wm/core/default_activation_client.h"
 
 #if defined(OS_FUCHSIA)
-#include <fuchsia/ui/policy/cpp/fidl.h>
-#include <lib/zx/eventpair.h>
-#include "base/fuchsia/component_context.h"
-#include "base/fuchsia/fuchsia_logging.h"
+#include "ui/platform_window/fuchsia/initialize_presenter_api_view.h"
 #endif
 
 #if defined(USE_OZONE)
@@ -115,17 +112,7 @@
   if (ui::OzonePlatform::GetInstance()
           ->GetPlatformProperties()
           .needs_view_token) {
-    // Create view_token and view_holder_token.
-    zx::eventpair view_holder_token;
-    zx_status_t status = zx::eventpair::create(
-        /*options=*/0, &properties.view_token, &view_holder_token);
-    ZX_CHECK(status == ZX_OK, status) << "zx_eventpair_create";
-
-    // Request Presenter to show the view full-screen.
-    auto presenter = base::fuchsia::ComponentContext::GetDefault()
-                         ->ConnectToService<fuchsia::ui::policy::Presenter>();
-
-    presenter->Present2(std::move(view_holder_token), nullptr);
+    ui::fuchsia::InitializeViewTokenAndPresentView(&properties);
   }
 #endif
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index ec556d25..139a6d5 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -48,8 +48,6 @@
     "../browser/background_fetch/mock_background_fetch_delegate.h",
     "../browser/fileapi/file_system_chooser_test_helpers.cc",
     "../browser/fileapi/file_system_chooser_test_helpers.h",
-    "../browser/media/session/mock_media_session_observer.cc",
-    "../browser/media/session/mock_media_session_observer.h",
     "../browser/media/session/mock_media_session_player_observer.cc",
     "../browser/media/session/mock_media_session_player_observer.h",
     "../browser/media/session/mock_media_session_service_impl.cc",
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index 180113ce..6ee446c 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -49,11 +49,16 @@
     # TODO(vmiura) check / generate reference images for Android devices
     self.Fail('Pixel_SolidColorBackground', ['mac', 'android'], bug=624256)
 
-    self.Fail('Pixel_CSSFilterEffects', ['mac', ('nvidia', 0xfe9)], bug=690277)
+    # TODO(wangxianzhu): This is commented out temporarily because of the entry
+    # for crbug.com/836884.
+    # self.Fail('Pixel_CSSFilterEffects', ['mac', ('nvidia', 0xfe9)],
+    #     bug=690277)
 
     # Became flaky on 10.13.6. When it flakes, it flakes 3 times, so
     # mark failing, unfortunately.
-    self.Fail('Pixel_CSSFilterEffects', ['highsierra', 'amd'], bug=872423)
+    # TODO(wangxianzhu): This is commented out temporarily because of the entry
+    # for crbug.com/836884.
+    # self.Fail('Pixel_CSSFilterEffects', ['highsierra', 'amd'], bug=872423)
 
     # TODO(kbr): flakily timing out on this configuration.
     self.Flaky('*', ['linux', 'intel', 'debug'], bug=648369)
@@ -116,6 +121,12 @@
     self.Flaky('Pixel_BackgroundImage',
         ['android', ('qualcomm', 'Adreno (TM) 418')], bug=883500)
 
+    # TODO(wangxianzhu): Re-enable after and rebaselining
+    self.Fail('Pixel_CSSFilterEffects', bug=836884)
+    self.Fail('Pixel_CSSFilterEffects_NoOverlays', bug=836884)
+    self.Fail('Pixel_2DCanvasWebGL', bug=836884)
+    self.Fail('Pixel_CSS3DBlueBox', bug=836884)
+
     # Fails on Mac Pro FYI Release (AMD)
     self.Fail('Pixel_Video_MP4',
         ['mac', ('amd', 0x679e)], bug=925744)
diff --git a/docs/code_coverage.md b/docs/code_coverage.md
index 342ff3c8..5097ef36 100644
--- a/docs/code_coverage.md
+++ b/docs/code_coverage.md
@@ -1,11 +1,14 @@
 # Code Coverage in Chromium
 
-### Coverage Dashboard: [https://chromium-coverage.appspot.com/]
+### Coverage Dashboard: [link](https://analysis.chromium.org/p/chromium/coverage)
 
 Table of contents:
 
-- [Coverage Script](#coverage-script)
-- [Workflow](#workflow)
+- [Coverage Infrastructure](#coverage-infra)
+  * [Coverage Builders](#coverage-builders)
+  * [Coverage Service](#coverage-service)
+  * [Coverage Clients](#coverage-clients)
+- [Local Coverage Script](#local-coverage-script)
   * [Step 0 Download Tooling](#step-0-download-tooling)
   * [Step 1 Build](#step-1-build)
   * [Step 2 Create Raw Profiles](#step-2-create-raw-profiles)
@@ -14,16 +17,106 @@
 - [Contacts](#contacts)
 - [FAQ](#faq)
 
-Chromium uses Clang source-based code coverage. This [documentation] explains
-how to use Clang’s source-based coverage features in general.
+Chromium uses source-based code coverage for clang-compiled languages such as
+C++. This [documentation] explains how to use Clang’s source-based coverage
+features in general.
 
-In this document, we first introduce a code coverage script that can be used to
-generate code coverage reports for Chromium code in one command, and then
-describe the code coverage reports generation workflow.
+In this document, we first introduce the code coverage infrastructure that
+continuously generates code coverage information for the whole codebase and for
+specific CLs in Gerrit. For the latter, refer to
+[code\_coverage\_in\_gerrit.md](code_coverage_in_gerrit.md).
+We then present a script that can be used to locally generate code coverage
+reports with one command, and finally we provide a description of the
+process of producing these reports.
 
-## Coverage Script
+## Coverage Infrastructure
+
+![coverage infra diagram]
+
+There are 3 layers in the system:
+
+### Coverage Builders
+
+The first layer is the LUCI builders that
+ - build instrumented targets,
+ - run the instrumented tests,
+ - merge the results into single streams,
+ - upload data to cloud storage.
+
+There are two types of builder:
+
+CI Builder
+
+The Code-coverage CI Builders periodically build all the test targets and fuzzer
+targets for a given platform and instrument all available source files. Then
+save the coverage data to a dedicated storage bucket.
+
+CQ Builder
+
+The code coverage CQ builders instrument only the files changed for a given CL.
+more information about per-cl coverage info in [this
+doc](code_coverage_in_gerrit.md).
+
+### Coverage Service
+
+The second layer in the system consists of an AppEngine application that
+consumes the coverage data from the builders above, structures it and stores it
+in cloud datastore. It then serves the information to the clients below.
+
+### Coverage Clients
+
+In the last layer we currently have two clients that consume the service:
+
+#### Coverage Dashboard
+
+The [coverage dashboard] front end is hosted in the same application as the
+service above.
+It shows the full-code coverage reports with links to the builds that generated
+them, as well as per-directory and per-component aggregation, and can be drilled
+down to the single line of code level of detail.
+
+Refer tho the following screenshots, or this [18-second video
+tutorial](https://www.youtube.com/watch?v=eX7im2_3YfA).
+
+##### Project View
+
+![coverage dashboard main view]
+
+##### Directory View
+
+![coverage dashboard directory view]
+
+##### Component View
+
+![coverage dashboard component view]
+
+##### Source View
+
+When you click on a particular source file in one of the views above, you can check
+per-line coverage information such as
+
+- Uncovered / Covered line fragments, lines and code blocks. This information can be
+useful to identify areas of code that lack test coverage.
+- Per-line hit counts indicating how many times this line was hit by all tested targets.
+This information can be useful to determine hot spots in your code.
+- Potentially dead code. See [dead code example].
+
+![coverage dashboard file view]
+
+#### Gerrit Coverage View
+
+The other client supported at the moment is the gerrit plugin for code coverage.
+
+![gerrit coverage view]
+
+See [this doc](code_coverage_in_gerrit.md) for information about the feature
+that allows gerrit to display code coverage information generated for a given CL
+by CQ bot. Or see this
+[15-second video tutorial](https://www.youtube.com/watch?v=cxXlYcSgIPE).
+
+## Local Coverage Script
 The [coverage script] automates the process described below and provides a
-one-stop service to generate code coverage reports in just one command.
+one-stop service to generate code coverage reports locally in just one command.
 
 This script is currently supported on Linux, Mac, iOS and ChromeOS platforms.
 
@@ -46,28 +139,8 @@
 directories.
 
 Aside from automating the process, this script provides visualization features to
-view code coverage breakdown by directories and by components, for example:
-
-### Directory View
-
-![code coverage report directory view]
-
-### Component View
-
-![code coverage report component view]
-
-### Source View
-
-When you click on a particular source file in one of the views above, you can check
-per-line coverage information such as
-
-- Uncovered / Covered line fragments, lines and code blocks. This information can be
-useful to identify areas of code that lack test coverage.
-- Per-line hit counts indicating how many times this line was hit by all tested targets.
-This information can be useful to determine hot spots in your code.
-- Potentially dead code. See [dead code example].
-
-![code coverage source view]
+view code coverage breakdown by directories and by components, similar to the
+views in the [coverage dashboard](#coverage-dashboard) above.
 
 ## Workflow
 This section presents the workflow of generating code coverage reports using two
@@ -81,7 +154,7 @@
 Generating code coverage reports requires llvm-profdata and llvm-cov tools.
 Currently, these two tools are not part of Chromium’s Clang bundle,
 [coverage script] downloads and updates them automatically, you can also
-download the tools manually ([link]).
+download the tools manually ([tools link]).
 
 ### Step 1 Build
 In Chromium, to compile code with coverage enabled, one needs to add
@@ -141,7 +214,7 @@
 report generation modes, and all of them require the following as input:
 - Indexed profile
 - All built target binaries
-- All exercised source files.
+- All exercised source files
 
 For example, the following command can be used to generate per-file line-by-line
 code coverage report:
@@ -223,16 +296,24 @@
 Source code of the dashboard is not open sourced at the moment, but if you are a
 Googler, you should have access to the code-coverage repository. There is a
 documentation and scripts for running it locally. To get access and report
-issues, ping chrome-code-coverage@ list.
+issues, ping the [code-coverage group].
+
+The code for the service and dashboard currently lives along with findit at
+[this location](https://chromium.googlesource.com/infra/infra/+/master/appengine/findit/)
+because of significant shared logic.
+
+The code used by the bots that generate the coverage data lives (among other
+places) in the
+[clang coverage recipe module](https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/slave/recipe_modules/clang_coverage/).
 
 ### Why is coverage for X not reported or unreasonably low, even though there is a test for X?
 
 There are several reasons why coverage reports can be incomplete or incorrect:
 
 * A particular test is not used for code coverage report generation. Please
-check the [test suite], and if the test is missing, upload a CL to add it.
-* A test may have a build failure or a runtime crash. Please check [the logs]
-for that particular test target (rightmost column on the [coverage dashboard]).
+[file a bug].
+* A test may have a build failure or a runtime crash. Please check the build
+for that particular report (rightmost column on the [coverage dashboard]).
 If there is any failure, please upload a CL with the fix. If you can't fix it,
 feel free to [file a bug].
 * A particular test may not be available on a particular platform. As of now,
@@ -249,11 +330,13 @@
 [assert]: http://man7.org/linux/man-pages/man3/assert.3.html
 [code-coverage group]: https://groups.google.com/a/chromium.org/forum/#!forum/code-coverage
 [code-coverage repository]: https://chrome-internal.googlesource.com/chrome/tools/code-coverage
-[coverage dashboard]: https://chromium-coverage.appspot.com/
+[coverage dashboard]: https://analysis.chromium.org/p/chromium/coverage
 [coverage script]: https://cs.chromium.org/chromium/src/tools/code_coverage/coverage.py
-[code coverage report directory view]: images/code_coverage_directory_view.png
-[code coverage report component view]: images/code_coverage_component_view.png
-[code coverage source view]: images/code_coverage_source_view.png
+[coverage infra diagram]: images/code_coverage_infra_diagram.png
+[coverage dashboard file view]: images/code_coverage_dashboard_file_view.png
+[coverage dashboard component view]: images/code_coverage_dashboard_component_view.png
+[coverage dashboard directory view]: images/code_coverage_dashboard_directory_view.png
+[coverage dashboard main view]: images/code_coverage_dashboard_main_view.png
 [crbug.com/821617]: https://crbug.com/821617
 [crbug.com/831939]: https://crbug.com/831939
 [crbug.com/834781]: https://crbug.com/834781
@@ -264,10 +347,9 @@
 [documentation]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
 [file a bug]: https://bugs.chromium.org/p/chromium/issues/entry?components=Tools%3ECodeCoverage
 [file a new issue]: https://bugs.chromium.org/p/chromium/issues/entry?components=Tools%3ECodeCoverage
+[gerrit coverage view]: images/code_coverage_uncovered_lines.png
 [guide]: http://llvm.org/docs/CommandGuide/llvm-cov.html
 [How do crashes affect code coverage?]: #how-do-crashes-affect-code-coverage
-[https://chromium-coverage.appspot.com/]: https://chromium-coverage.appspot.com/
 [known issues]: https://bugs.chromium.org/p/chromium/issues/list?q=component:Tools%3ECodeCoverage
-[link]: https://storage.googleapis.com/chromium-browser-clang-staging/
+[tools link]: https://storage.googleapis.com/chromium-browser-clang-staging/
 [test suite]: https://cs.chromium.org/chromium/src/tools/code_coverage/test_suite.txt
-[the logs]: https://chromium-coverage.appspot.com/reports/latest/linux/metadata/index.html
diff --git a/docs/images/code_coverage_component_view.png b/docs/images/code_coverage_component_view.png
deleted file mode 100644
index 0ee3159..0000000
--- a/docs/images/code_coverage_component_view.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/code_coverage_dashboard_component_view.png b/docs/images/code_coverage_dashboard_component_view.png
new file mode 100644
index 0000000..f594792
--- /dev/null
+++ b/docs/images/code_coverage_dashboard_component_view.png
Binary files differ
diff --git a/docs/images/code_coverage_dashboard_directory_view.png b/docs/images/code_coverage_dashboard_directory_view.png
new file mode 100644
index 0000000..c91a723
--- /dev/null
+++ b/docs/images/code_coverage_dashboard_directory_view.png
Binary files differ
diff --git a/docs/images/code_coverage_dashboard_file_view.png b/docs/images/code_coverage_dashboard_file_view.png
new file mode 100644
index 0000000..3878073
--- /dev/null
+++ b/docs/images/code_coverage_dashboard_file_view.png
Binary files differ
diff --git a/docs/images/code_coverage_dashboard_main_view.png b/docs/images/code_coverage_dashboard_main_view.png
new file mode 100644
index 0000000..fc4e23d
--- /dev/null
+++ b/docs/images/code_coverage_dashboard_main_view.png
Binary files differ
diff --git a/docs/images/code_coverage_directory_view.png b/docs/images/code_coverage_directory_view.png
deleted file mode 100644
index 50ecd88..0000000
--- a/docs/images/code_coverage_directory_view.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/code_coverage_infra_diagram.png b/docs/images/code_coverage_infra_diagram.png
new file mode 100644
index 0000000..1069935
--- /dev/null
+++ b/docs/images/code_coverage_infra_diagram.png
Binary files differ
diff --git a/docs/images/code_coverage_source_view.png b/docs/images/code_coverage_source_view.png
deleted file mode 100644
index ab83003..0000000
--- a/docs/images/code_coverage_source_view.png
+++ /dev/null
Binary files differ
diff --git a/docs/images/code_coverage_workflow.png b/docs/images/code_coverage_workflow.png
index 284be2f..aafdd079 100644
--- a/docs/images/code_coverage_workflow.png
+++ b/docs/images/code_coverage_workflow.png
Binary files differ
diff --git a/docs/vscode.md b/docs/vscode.md
index 3d6f588..9b40e11 100644
--- a/docs/vscode.md
+++ b/docs/vscode.md
@@ -55,7 +55,6 @@
 Code does not require project or solution files. However, it does store
 workspace settings in a `.vscode` folder in your base directory.
 
-
 ### Fixes for Known Issues
 
 #### Git on Windows
diff --git a/fuchsia/fidl/cast/application_config.fidl b/fuchsia/fidl/cast/application_config.fidl
index a312e26..569d32d 100644
--- a/fuchsia/fidl/cast/application_config.fidl
+++ b/fuchsia/fidl/cast/application_config.fidl
@@ -20,5 +20,5 @@
 [Discoverable]
 interface ApplicationConfigManager {
   /// Returns the ApplicationConfig for the specified application Id.
-  1: GetConfig(string id) -> (ApplicationConfig? config);
+  GetConfig(string id) -> (ApplicationConfig? config);
 };
diff --git a/fuchsia/fidl/cast/cast_channel.fidl b/fuchsia/fidl/cast/cast_channel.fidl
index 3ec3374fb..77a88d0 100644
--- a/fuchsia/fidl/cast/cast_channel.fidl
+++ b/fuchsia/fidl/cast/cast_channel.fidl
@@ -12,6 +12,6 @@
   /// The new Cast Channel's message port is returned asynchronously once
   /// opened by the webpage. The port is disconnected when the peer's Cast
   /// Channel is closed.
-  1: Connect() -> (chromium.web.MessagePort channel);
+  Connect() -> (chromium.web.MessagePort channel);
 };
 
diff --git a/gpu/command_buffer/service/gl_surface_mock.h b/gpu/command_buffer/service/gl_surface_mock.h
index 948bc59..7812ab7 100644
--- a/gpu/command_buffer/service/gl_surface_mock.h
+++ b/gpu/command_buffer/service/gl_surface_mock.h
@@ -24,14 +24,13 @@
                     ColorSpace color_space,
                     bool alpha));
   MOCK_METHOD0(IsOffscreen, bool());
-  MOCK_METHOD1(SwapBuffers,
-               gfx::SwapResult(const PresentationCallback& callback));
+  MOCK_METHOD1(SwapBuffers, gfx::SwapResult(PresentationCallback callback));
   MOCK_METHOD5(PostSubBuffer,
                gfx::SwapResult(int x,
                                int y,
                                int width,
                                int height,
-                               const PresentationCallback& callback));
+                               PresentationCallback callback));
   MOCK_METHOD0(SupportsPostSubBuffer, bool());
   MOCK_METHOD0(GetSize, gfx::Size());
   MOCK_METHOD0(GetHandle, void*());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 2ba78ea..ec7662313 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -13040,8 +13040,8 @@
     client_->OnSwapBuffers(c.swap_id(), c.flags);
     surface_->PostSubBufferAsync(
         c.x, c.y, c.width, c.height,
-        base::Bind(&GLES2DecoderImpl::FinishAsyncSwapBuffers,
-                   weak_ptr_factory_.GetWeakPtr(), c.swap_id()),
+        base::BindOnce(&GLES2DecoderImpl::FinishAsyncSwapBuffers,
+                       weak_ptr_factory_.GetWeakPtr(), c.swap_id()),
         base::DoNothing());
   } else {
     client_->OnSwapBuffers(c.swap_id(), c.flags);
@@ -16260,8 +16260,8 @@
 
     client_->OnSwapBuffers(swap_id, flags);
     surface_->SwapBuffersAsync(
-        base::Bind(&GLES2DecoderImpl::FinishAsyncSwapBuffers,
-                   weak_ptr_factory_.GetWeakPtr(), swap_id),
+        base::BindOnce(&GLES2DecoderImpl::FinishAsyncSwapBuffers,
+                       weak_ptr_factory_.GetWeakPtr(), swap_id),
         base::DoNothing());
   } else {
     client_->OnSwapBuffers(swap_id, flags);
@@ -16313,8 +16313,8 @@
   if (supports_async_swap_) {
     client_->OnSwapBuffers(swap_id, flags);
     surface_->CommitOverlayPlanesAsync(
-        base::Bind(&GLES2DecoderImpl::FinishAsyncSwapBuffers,
-                   weak_ptr_factory_.GetWeakPtr(), swap_id),
+        base::BindOnce(&GLES2DecoderImpl::FinishAsyncSwapBuffers,
+                       weak_ptr_factory_.GetWeakPtr(), swap_id),
         base::DoNothing());
   } else {
     client_->OnSwapBuffers(swap_id, flags);
diff --git a/gpu/ipc/service/direct_composition_child_surface_win.cc b/gpu/ipc/service/direct_composition_child_surface_win.cc
index 886dff6..3088286 100644
--- a/gpu/ipc/service/direct_composition_child_surface_win.cc
+++ b/gpu/ipc/service/direct_composition_child_surface_win.cc
@@ -216,7 +216,7 @@
 }
 
 gfx::SwapResult DirectCompositionChildSurfaceWin::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   // PresentationCallback is handled by DirectCompositionSurfaceWin. The child
   // surface doesn't need provide presentation feedback.
   DCHECK(!callback);
diff --git a/gpu/ipc/service/direct_composition_child_surface_win.h b/gpu/ipc/service/direct_composition_child_surface_win.h
index a91071e..52cbce9 100644
--- a/gpu/ipc/service/direct_composition_child_surface_win.h
+++ b/gpu/ipc/service/direct_composition_child_surface_win.h
@@ -26,7 +26,7 @@
   gfx::Size GetSize() override;
   bool IsOffscreen() override;
   void* GetHandle() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   bool FlipsVertically() const override;
   bool SupportsPostSubBuffer() override;
   bool OnMakeCurrent(gl::GLContext* context) override;
diff --git a/gpu/ipc/service/direct_composition_surface_win.cc b/gpu/ipc/service/direct_composition_surface_win.cc
index 46710ba..be3b81a 100644
--- a/gpu/ipc/service/direct_composition_surface_win.cc
+++ b/gpu/ipc/service/direct_composition_surface_win.cc
@@ -8,6 +8,8 @@
 #include <dcomptypes.h>
 #include <dxgi1_6.h>
 
+#include <utility>
+
 #include "base/containers/circular_deque.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
@@ -1871,9 +1873,9 @@
 }
 
 gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   gl::GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
-      presentation_helper_.get(), callback);
+      presentation_helper_.get(), std::move(callback));
 
   bool succeeded = true;
   if (root_surface_->SwapBuffers(PresentationCallback()) ==
@@ -1900,10 +1902,10 @@
     int y,
     int width,
     int height,
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   // The arguments are ignored because SetDrawRectangle specified the area to
   // be swapped.
-  return SwapBuffers(callback);
+  return SwapBuffers(std::move(callback));
 }
 
 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() {
diff --git a/gpu/ipc/service/direct_composition_surface_win.h b/gpu/ipc/service/direct_composition_surface_win.h
index 703e4ab..b0217bb 100644
--- a/gpu/ipc/service/direct_composition_surface_win.h
+++ b/gpu/ipc/service/direct_composition_surface_win.h
@@ -70,12 +70,12 @@
               float scale_factor,
               ColorSpace color_space,
               bool has_alpha) override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::SwapResult PostSubBuffer(int x,
                                 int y,
                                 int width,
                                 int height,
-                                const PresentationCallback& callback) override;
+                                PresentationCallback callback) override;
   gfx::VSyncProvider* GetVSyncProvider() override;
   void SetVSyncEnabled(bool enabled) override;
   bool SetEnableDCLayers(bool enable) override;
diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.h b/gpu/ipc/service/image_transport_surface_overlay_mac.h
index 5d68c4f..8b9e387 100644
--- a/gpu/ipc/service/image_transport_surface_overlay_mac.h
+++ b/gpu/ipc/service/image_transport_surface_overlay_mac.h
@@ -45,12 +45,12 @@
               ColorSpace color_space,
               bool has_alpha) override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::SwapResult PostSubBuffer(int x,
                                 int y,
                                 int width,
                                 int height,
-                                const PresentationCallback& callback) override;
+                                PresentationCallback callback) override;
   bool SupportsPostSubBuffer() override;
   gfx::Size GetSize() override;
   void* GetHandle() override;
@@ -76,9 +76,9 @@
   ~ImageTransportSurfaceOverlayMac() override;
 
   gfx::SwapResult SwapBuffersInternal(const gfx::Rect& pixel_damage_rect,
-                                      const PresentationCallback& callback);
+                                      PresentationCallback callback);
   void ApplyBackpressure();
-  void BufferPresented(const PresentationCallback& callback,
+  void BufferPresented(PresentationCallback callback,
                        const gfx::PresentationFeedback& feedback);
 
   base::WeakPtr<ImageTransportSurfaceDelegate> delegate_;
diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.mm b/gpu/ipc/service/image_transport_surface_overlay_mac.mm
index 54e8912..67d26f0 100644
--- a/gpu/ipc/service/image_transport_surface_overlay_mac.mm
+++ b/gpu/ipc/service/image_transport_surface_overlay_mac.mm
@@ -90,17 +90,17 @@
 }
 
 void ImageTransportSurfaceOverlayMac::BufferPresented(
-    const PresentationCallback& callback,
+    PresentationCallback callback,
     const gfx::PresentationFeedback& feedback) {
   DCHECK(!callback.is_null());
-  callback.Run(feedback);
+  std::move(callback).Run(feedback);
   if (delegate_)
     delegate_->BufferPresented(feedback);
 }
 
 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal(
     const gfx::Rect& pixel_damage_rect,
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffersInternal");
 
   // Do a GL fence for flush to apply back-pressure before drawing.
@@ -167,14 +167,16 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&ImageTransportSurfaceOverlayMac::BufferPresented,
-                     weak_ptr_factory_.GetWeakPtr(), callback, feedback));
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+                     feedback));
   return gfx::SwapResult::SWAP_ACK;
 }
 
 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   return SwapBuffersInternal(
-      gfx::Rect(0, 0, pixel_size_.width(), pixel_size_.height()), callback);
+      gfx::Rect(0, 0, pixel_size_.width(), pixel_size_.height()),
+      std::move(callback));
 }
 
 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(
@@ -182,8 +184,9 @@
     int y,
     int width,
     int height,
-    const PresentationCallback& callback) {
-  return SwapBuffersInternal(gfx::Rect(x, y, width, height), callback);
+    PresentationCallback callback) {
+  return SwapBuffersInternal(gfx::Rect(x, y, width, height),
+                             std::move(callback));
 }
 
 bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() {
diff --git a/gpu/ipc/service/pass_through_image_transport_surface.cc b/gpu/ipc/service/pass_through_image_transport_surface.cc
index 8827552..6b1b9fc9 100644
--- a/gpu/ipc/service/pass_through_image_transport_surface.cc
+++ b/gpu/ipc/service/pass_through_image_transport_surface.cc
@@ -4,6 +4,8 @@
 
 #include "gpu/ipc/service/pass_through_image_transport_surface.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
@@ -51,20 +53,20 @@
 }
 
 gfx::SwapResult PassThroughImageTransportSurface::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   gfx::SwapResponse response;
   StartSwapBuffers(&response);
   gfx::SwapResult result = gl::GLSurfaceAdapter::SwapBuffers(
-      base::Bind(&PassThroughImageTransportSurface::BufferPresented,
-                 weak_ptr_factory_.GetWeakPtr(), callback));
+      base::BindOnce(&PassThroughImageTransportSurface::BufferPresented,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   response.result = result;
   FinishSwapBuffers(std::move(response));
   return result;
 }
 
 void PassThroughImageTransportSurface::SwapBuffersAsync(
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
   gfx::SwapResponse response;
   StartSwapBuffers(&response);
 
@@ -73,21 +75,23 @@
   // is destroyed. However, this also means that the callback can be run on
   // the calling thread only.
   gl::GLSurfaceAdapter::SwapBuffersAsync(
-      base::Bind(&PassThroughImageTransportSurface::FinishSwapBuffersAsync,
-                 weak_ptr_factory_.GetWeakPtr(), completion_callback,
-                 base::Passed(&response)),
-      base::Bind(&PassThroughImageTransportSurface::BufferPresented,
-                 weak_ptr_factory_.GetWeakPtr(), presentation_callback));
+      base::BindOnce(&PassThroughImageTransportSurface::FinishSwapBuffersAsync,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(completion_callback), std::move(response)),
+      base::BindOnce(&PassThroughImageTransportSurface::BufferPresented,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(presentation_callback)));
 }
 
 gfx::SwapResult PassThroughImageTransportSurface::SwapBuffersWithBounds(
     const std::vector<gfx::Rect>& rects,
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   gfx::SwapResponse response;
   StartSwapBuffers(&response);
   gfx::SwapResult result = gl::GLSurfaceAdapter::SwapBuffersWithBounds(
-      rects, base::Bind(&PassThroughImageTransportSurface::BufferPresented,
-                        weak_ptr_factory_.GetWeakPtr(), callback));
+      rects,
+      base::BindOnce(&PassThroughImageTransportSurface::BufferPresented,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   response.result = result;
   FinishSwapBuffers(std::move(response));
   return result;
@@ -98,13 +102,13 @@
     int y,
     int width,
     int height,
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   gfx::SwapResponse response;
   StartSwapBuffers(&response);
   gfx::SwapResult result = gl::GLSurfaceAdapter::PostSubBuffer(
       x, y, width, height,
-      base::Bind(&PassThroughImageTransportSurface::BufferPresented,
-                 weak_ptr_factory_.GetWeakPtr(), callback));
+      base::BindOnce(&PassThroughImageTransportSurface::BufferPresented,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   response.result = result;
   FinishSwapBuffers(std::move(response));
 
@@ -116,42 +120,44 @@
     int y,
     int width,
     int height,
-    const GLSurface::SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
   gfx::SwapResponse response;
   StartSwapBuffers(&response);
   gl::GLSurfaceAdapter::PostSubBufferAsync(
       x, y, width, height,
-      base::Bind(&PassThroughImageTransportSurface::FinishSwapBuffersAsync,
-                 weak_ptr_factory_.GetWeakPtr(), completion_callback,
-                 base::Passed(&response)),
-      base::Bind(&PassThroughImageTransportSurface::BufferPresented,
-                 weak_ptr_factory_.GetWeakPtr(), presentation_callback));
+      base::BindOnce(&PassThroughImageTransportSurface::FinishSwapBuffersAsync,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(completion_callback), std::move(response)),
+      base::BindOnce(&PassThroughImageTransportSurface::BufferPresented,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(presentation_callback)));
 }
 
 gfx::SwapResult PassThroughImageTransportSurface::CommitOverlayPlanes(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   gfx::SwapResponse response;
   StartSwapBuffers(&response);
   gfx::SwapResult result = gl::GLSurfaceAdapter::CommitOverlayPlanes(
-      base::Bind(&PassThroughImageTransportSurface::BufferPresented,
-                 weak_ptr_factory_.GetWeakPtr(), callback));
+      base::BindOnce(&PassThroughImageTransportSurface::BufferPresented,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   response.result = result;
   FinishSwapBuffers(std::move(response));
   return result;
 }
 
 void PassThroughImageTransportSurface::CommitOverlayPlanesAsync(
-    const GLSurface::SwapCompletionCallback& callback,
-    const PresentationCallback& presentation_callback) {
+    SwapCompletionCallback callback,
+    PresentationCallback presentation_callback) {
   gfx::SwapResponse response;
   StartSwapBuffers(&response);
   gl::GLSurfaceAdapter::CommitOverlayPlanesAsync(
-      base::Bind(&PassThroughImageTransportSurface::FinishSwapBuffersAsync,
-                 weak_ptr_factory_.GetWeakPtr(), callback,
-                 base::Passed(&response)),
-      base::Bind(&PassThroughImageTransportSurface::BufferPresented,
-                 weak_ptr_factory_.GetWeakPtr(), presentation_callback));
+      base::BindOnce(&PassThroughImageTransportSurface::FinishSwapBuffersAsync,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+                     std::move(response)),
+      base::BindOnce(&PassThroughImageTransportSurface::BufferPresented,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(presentation_callback)));
 }
 
 void PassThroughImageTransportSurface::SetVSyncEnabled(bool enabled) {
@@ -218,7 +224,7 @@
 }
 
 void PassThroughImageTransportSurface::FinishSwapBuffersAsync(
-    GLSurface::SwapCompletionCallback callback,
+    SwapCompletionCallback callback,
     gfx::SwapResponse response,
     gfx::SwapResult result,
     std::unique_ptr<gfx::GpuFence> gpu_fence) {
@@ -230,14 +236,14 @@
     gpu_fence->Wait();
   response.result = result;
   FinishSwapBuffers(std::move(response));
-  callback.Run(result, nullptr);
+  std::move(callback).Run(result, nullptr);
 }
 
 void PassThroughImageTransportSurface::BufferPresented(
-    const GLSurface::PresentationCallback& callback,
+    GLSurface::PresentationCallback callback,
     const gfx::PresentationFeedback& feedback) {
   DCHECK(allow_running_presentation_callback_);
-  callback.Run(feedback);
+  std::move(callback).Run(feedback);
   if (delegate_)
     delegate_->BufferPresented(feedback);
 }
diff --git a/gpu/ipc/service/pass_through_image_transport_surface.h b/gpu/ipc/service/pass_through_image_transport_surface.h
index 279bfa3..8defdd04 100644
--- a/gpu/ipc/service/pass_through_image_transport_surface.h
+++ b/gpu/ipc/service/pass_through_image_transport_surface.h
@@ -29,30 +29,26 @@
 
   // GLSurface implementation.
   bool Initialize(gl::GLSurfaceFormat format) override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
-  void SwapBuffersAsync(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
-  gfx::SwapResult SwapBuffersWithBounds(
-      const std::vector<gfx::Rect>& rects,
-      const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
+  void SwapBuffersAsync(SwapCompletionCallback completion_callback,
+                        PresentationCallback presentation_callback) override;
+  gfx::SwapResult SwapBuffersWithBounds(const std::vector<gfx::Rect>& rects,
+                                        PresentationCallback callback) override;
   gfx::SwapResult PostSubBuffer(int x,
                                 int y,
                                 int width,
                                 int height,
-                                const PresentationCallback& callback) override;
-  void PostSubBufferAsync(
-      int x,
-      int y,
-      int width,
-      int height,
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
-  gfx::SwapResult CommitOverlayPlanes(
-      const PresentationCallback& callback) override;
+                                PresentationCallback callback) override;
+  void PostSubBufferAsync(int x,
+                          int y,
+                          int width,
+                          int height,
+                          SwapCompletionCallback completion_callback,
+                          PresentationCallback presentation_callback) override;
+  gfx::SwapResult CommitOverlayPlanes(PresentationCallback callback) override;
   void CommitOverlayPlanesAsync(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
+      SwapCompletionCallback completion_callback,
+      PresentationCallback presentation_callback) override;
   void SetVSyncEnabled(bool enabled) override;
 
  private:
@@ -62,12 +58,12 @@
 
   void StartSwapBuffers(gfx::SwapResponse* response);
   void FinishSwapBuffers(gfx::SwapResponse response);
-  void FinishSwapBuffersAsync(GLSurface::SwapCompletionCallback callback,
+  void FinishSwapBuffersAsync(SwapCompletionCallback callback,
                               gfx::SwapResponse response,
                               gfx::SwapResult result,
                               std::unique_ptr<gfx::GpuFence> gpu_fence);
 
-  void BufferPresented(const GLSurface::PresentationCallback& callback,
+  void BufferPresented(PresentationCallback callback,
                        const gfx::PresentationFeedback& feedback);
 
   const bool is_gpu_vsync_disabled_;
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 81f6c50c..fd8ab82 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -1292,6 +1292,12 @@
     }
 
     builders {
+      name: "Linux FYI Experimental Release (Intel HD 630)"
+      mixins: "gpu-slow-bot"
+      mixins: "linux-gpu-fyi-ci"
+    }
+
+    builders {
       name: "Linux FYI Release (NVIDIA)"
       mixins: "linux-gpu-fyi-ci"
     }
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 3db9a5e1..18aed07 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -2791,20 +2791,18 @@
   repo_url: "https://chromium.googlesource.com/chromium/src"
   refs: "refs/heads/master"
   manifest_name: "REVISION"
+  include_experimental_builds: true
   builders {
-    name: "buildbot/chromium.goma/Chromium Linux Goma Staging"
     name: "buildbucket/luci.chromium.ci/Chromium Linux Goma Staging"
     category: "clients5"
     short_name: "lnx"
   }
   builders {
-    name: "buildbot/chromium.goma/Chromium Mac Goma Staging"
     name: "buildbucket/luci.chromium.ci/Chromium Mac Goma Staging"
     category: "clients5"
     short_name: "mac"
   }
   builders {
-    name: "buildbot/chromium.goma/CrWinGomaStaging"
     name: "buildbucket/luci.chromium.ci/CrWinGomaStaging"
     category: "clients5"
     short_name: "win"
@@ -2827,24 +2825,20 @@
     category: "rbe|tot|android arm|rel"
   }
   builders {
-    name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging (clobber)"
     name: "buildbucket/luci.chromium.ci/Chromium Linux Goma RBE Staging (clobber)"
     category: "rbe|staging|linux|rel"
     short_name: "clb"
   }
   builders {
-    name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging"
     name: "buildbucket/luci.chromium.ci/Chromium Linux Goma RBE Staging"
     category: "rbe|staging|linux|rel"
   }
   builders {
-    name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging (dbg) (clobber)"
     name: "buildbucket/luci.chromium.ci/Chromium Linux Goma RBE Staging (dbg) (clobber)"
     category: "rbe|staging|linux|debug"
     short_name: "clb"
   }
   builders {
-    name: "buildbot/chromium.goma/Chromium Linux Goma RBE Staging (dbg)"
     name: "buildbucket/luci.chromium.ci/Chromium Linux Goma RBE Staging (dbg)"
     category: "rbe|staging|linux|debug"
   }
@@ -3239,6 +3233,11 @@
     short_name: "dqp"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Linux FYI Experimental Release (Intel HD 630)"
+    category: "Linux|Intel"
+    short_name: "rel"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Linux FYI Release (Intel HD 630)"
     category: "Linux|Intel"
     short_name: "rel"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index 8b897e3..a9a20cdc 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -1393,6 +1393,17 @@
 }
 
 job {
+  id: "Linux FYI Experimental Release (Intel HD 630)"
+  # Triggered by "GPU FYI Linux Builder".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Linux FYI Experimental Release (Intel HD 630)"
+  }
+}
+
+job {
   id: "Linux FYI Release (AMD R7 240)"
   # Triggered by "GPU FYI Linux Builder".
   acl_sets: "triggered-by-parent-builders"
diff --git a/ios/chrome/browser/translate/translate_infobar_controller.mm b/ios/chrome/browser/translate/translate_infobar_controller.mm
index fea3d620..2cfce6a 100644
--- a/ios/chrome/browser/translate/translate_infobar_controller.mm
+++ b/ios/chrome/browser/translate/translate_infobar_controller.mm
@@ -135,6 +135,7 @@
       break;
     case translate::TranslateStep::TRANSLATE_STEP_TRANSLATE_ERROR:
       _infobarView.state = TranslateInfobarViewStateBeforeTranslate;
+      [self.translateNotificationHandler showTranslateErrorNotification];
   }
 }
 
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 2496c62..0f826b98 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -2372,9 +2372,12 @@
       // Always show the webState view under the NTP, to work around
       // crbug.com/848789
       if (base::FeatureList::IsEnabled(kBrowserContainerKeepsContentView)) {
-        if (self.browserContainerViewController.contentView == nil)
+        if (self.browserContainerViewController.contentView == nil) {
           self.browserContainerViewController.contentView =
               tab.webState->GetView();
+        }
+        self.browserContainerViewController.contentView.frame =
+            self.contentArea.bounds;
       } else {
         self.browserContainerViewController.contentView = nil;
       }
diff --git a/ios/chrome/browser/ui/translate/translate_notification_handler.h b/ios/chrome/browser/ui/translate/translate_notification_handler.h
index bcb3361..150f5edd 100644
--- a/ios/chrome/browser/ui/translate/translate_notification_handler.h
+++ b/ios/chrome/browser/ui/translate/translate_notification_handler.h
@@ -31,6 +31,10 @@
 - (void)showNeverTranslateSiteNotificationWithDelegate:
     (id<TranslateNotificationDelegate>)delegate;
 
+// Tells the handler to display a notification that the page could not be
+// translated.
+- (void)showTranslateErrorNotification;
+
 // Tells the handler to stop displaying the notification, if any.
 - (void)dismissNotification;
 
diff --git a/ios/chrome/browser/ui/translate/translate_notification_presenter.mm b/ios/chrome/browser/ui/translate/translate_notification_presenter.mm
index da3ba219..0677ccf8 100644
--- a/ios/chrome/browser/ui/translate/translate_notification_presenter.mm
+++ b/ios/chrome/browser/ui/translate/translate_notification_presenter.mm
@@ -108,6 +108,11 @@
            completionHandler:completion];
 }
 
+- (void)showTranslateErrorNotification {
+  NSString* text = l10n_util::GetNSString(IDS_TRANSLATE_NOTIFICATION_ERROR);
+  [self showSnackbarWithText:text actionHandler:nil completionHandler:nil];
+}
+
 - (void)dismissNotification {
   [MDCSnackbarManager dismissAndCallCompletionBlocksWithCategory:
                           kTranslateNotificationSnackbarCategory];
@@ -118,12 +123,16 @@
 - (void)showSnackbarWithText:(NSString*)text
                actionHandler:(void (^)())actionHandler
            completionHandler:(void (^)(BOOL))completionHandler {
-  MDCSnackbarMessageAction* action = [[MDCSnackbarMessageAction alloc] init];
-  action.title = l10n_util::GetNSString(IDS_TRANSLATE_NOTIFICATION_UNDO);
-  action.accessibilityIdentifier = kSnackbarActionAccessibilityIdentifier;
-  action.handler = actionHandler;
   MDCSnackbarMessage* message = [MDCSnackbarMessage messageWithText:text];
-  message.action = action;
+  if (actionHandler) {
+    // A MDCSnackbarMessageAction is displayed as a button on the Snackbar. If
+    // no action is set no button will appear on the Snackbar.
+    MDCSnackbarMessageAction* action = [[MDCSnackbarMessageAction alloc] init];
+    action.title = l10n_util::GetNSString(IDS_TRANSLATE_NOTIFICATION_UNDO);
+    action.accessibilityIdentifier = kSnackbarActionAccessibilityIdentifier;
+    action.handler = actionHandler;
+    message.action = action;
+  }
   message.completionHandler = completionHandler;
   message.category = kTranslateNotificationSnackbarCategory;
   TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess);
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index de7e5d43..9fc7217 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1718,6 +1718,12 @@
   if (_webUIManager)
     return;
 
+  if (!self.currentNavItem) {
+    // TODO(crbug.com/925304): Pending item (which stores the holder) should be
+    // owned by NavigationContext object. Pending item should never be null.
+    return;
+  }
+
   web::WKBackForwardListItemHolder* holder =
       [self currentBackForwardListItemHolder];
 
@@ -2933,7 +2939,10 @@
   // keep it since it will have a more accurate URL and policy than what can
   // be extracted from the landing page.)
   web::NavigationItem* currentItem = self.currentNavItem;
-  if (!currentItem->GetReferrer().url.is_valid()) {
+
+  // TODO(crbug.com/925304): Pending item (which should be used here) should be
+  // owned by NavigationContext object. Pending item should never be null.
+  if (currentItem && !currentItem->GetReferrer().url.is_valid()) {
     currentItem->SetReferrer(referrer);
   }
 
@@ -4935,15 +4944,21 @@
   }
 
   [self commitPendingNavigationInfo];
-  if ([self currentBackForwardListItemHolder]->navigation_type() ==
-      WKNavigationTypeBackForward) {
-    // A fast back/forward won't call decidePolicyForNavigationResponse, so
-    // the MIME type needs to be updated explicitly.
-    NSString* storedMIMEType =
-        [self currentBackForwardListItemHolder]->mime_type();
-    if (storedMIMEType) {
-      self.webStateImpl->SetContentsMimeType(
-          base::SysNSStringToUTF8(storedMIMEType));
+
+  // TODO(crbug.com/925304): Pending item (which is stores
+  // currentBackForwardListItemHolder) should be owned by NavigationContext.
+  // Pending item should never be null.
+  if (self.currentNavItem) {
+    if ([self currentBackForwardListItemHolder]
+        -> navigation_type() == WKNavigationTypeBackForward) {
+      // A fast back/forward won't call decidePolicyForNavigationResponse, so
+      // the MIME type needs to be updated explicitly.
+      NSString* storedMIMEType =
+          [self currentBackForwardListItemHolder] -> mime_type();
+      if (storedMIMEType) {
+        self.webStateImpl->SetContentsMimeType(
+            base::SysNSStringToUTF8(storedMIMEType));
+      }
     }
   }
 
diff --git a/media/blink/renderer_media_player_interface.h b/media/blink/renderer_media_player_interface.h
deleted file mode 100644
index d95338d..0000000
--- a/media/blink/renderer_media_player_interface.h
+++ /dev/null
@@ -1,122 +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 MEDIA_BLINK_RENDERER_MEDIA_PLAYER_INTERFACE_H_
-#define MEDIA_BLINK_RENDERER_MEDIA_PLAYER_INTERFACE_H_
-
-// This file contains interfaces modeled after classes in
-// content/renderer/media/android for the purposes of letting clases in
-// this directory implement and/or interact with those classes.
-// It's a stop-gap used to support cast on android until a better solution
-// is implemented: crbug/575276
-
-#include <string>
-#include "base/time/time.h"
-#include "media/blink/webmediaplayer_delegate.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "url/gurl.h"
-
-namespace blink {
-enum class WebRemotePlaybackAvailability;
-}
-
-// Dictates which type of media playback is being initialized.
-enum MediaPlayerHostMsg_Initialize_Type {
-  MEDIA_PLAYER_TYPE_URL,
-  MEDIA_PLAYER_TYPE_REMOTE_ONLY,
-  MEDIA_PLAYER_TYPE_LAST = MEDIA_PLAYER_TYPE_REMOTE_ONLY
-};
-
-namespace media {
-
-class RendererMediaPlayerInterface {
- public:
-  virtual void OnMediaMetadataChanged(base::TimeDelta duration,
-                                      int width,
-                                      int height,
-                                      bool success) = 0;
-  virtual void OnPlaybackComplete() = 0;
-  virtual void OnBufferingUpdate(int percentage) = 0;
-  virtual void OnSeekRequest(base::TimeDelta time_to_seek) = 0;
-  virtual void OnSeekComplete(base::TimeDelta current_time) = 0;
-  virtual void OnMediaError(int error_type) = 0;
-  virtual void OnVideoSizeChanged(int width, int height) = 0;
-
-  // Called to update the current time.
-  virtual void OnTimeUpdate(base::TimeDelta current_timestamp,
-                            base::TimeTicks current_time_ticks) = 0;
-
-  virtual void OnPlayerReleased() = 0;
-
-  // Functions called when media player status changes.
-  virtual void OnConnectedToRemoteDevice(
-      const std::string& remote_playback_message) = 0;
-  virtual void OnDisconnectedFromRemoteDevice() = 0;
-  virtual void OnRemotePlaybackStarted() = 0;
-  virtual void OnCancelledRemotePlaybackRequest() = 0;
-  virtual void OnDidExitFullscreen() = 0;
-  virtual void OnMediaPlayerPlay() = 0;
-  virtual void OnMediaPlayerPause() = 0;
-  virtual void OnRemoteRouteAvailabilityChanged(
-      blink::WebRemotePlaybackAvailability availability) = 0;
-
-  // This function is called by the RendererMediaPlayerManager to pause the
-  // video and release the media player and surface texture when we switch tabs.
-  // However, the actual GlTexture is not released to keep the video screenshot.
-  virtual void SuspendAndReleaseResources() = 0;
-};
-
-class RendererMediaPlayerManagerInterface {
- public:
-  // Initializes a MediaPlayerAndroid object in browser process.
-  virtual void Initialize(MediaPlayerHostMsg_Initialize_Type type,
-                          int player_id,
-                          const GURL& url,
-                          const GURL& site_for_cookies,
-                          const GURL& frame_url,
-                          bool allow_credentials,
-                          int delegate_id) = 0;
-
-  // Starts the player.
-  virtual void Start(int player_id) = 0;
-
-  // Pauses the player.
-  // is_media_related_action should be true if this pause is coming from an
-  // an action that explicitly pauses the video (user pressing pause, JS, etc.)
-  // Otherwise it should be false if Pause is being called due to other reasons
-  // (cleanup, freeing resources, etc.)
-  virtual void Pause(int player_id, bool is_media_related_action) = 0;
-
-  // Performs seek on the player.
-  virtual void Seek(int player_id, base::TimeDelta time) = 0;
-
-  // Sets the player volume.
-  virtual void SetVolume(int player_id, double volume) = 0;
-
-  // Sets the poster image.
-  virtual void SetPoster(int player_id, const GURL& poster) = 0;
-
-  // Releases resources for the player after being suspended.
-  virtual void SuspendAndReleaseResources(int player_id) = 0;
-
-  // Destroys the player in the browser process
-  virtual void DestroyPlayer(int player_id) = 0;
-
-  // Requests remote playback if possible
-  virtual void RequestRemotePlayback(int player_id) = 0;
-
-  // Requests control of remote playback
-  virtual void RequestRemotePlaybackControl(int player_id) = 0;
-
-  // Requests stopping remote playback
-  virtual void RequestRemotePlaybackStop(int player_id) = 0;
-
-  // Registers and unregisters a RendererMediaPlayerInterface object.
-  virtual int RegisterMediaPlayer(RendererMediaPlayerInterface* player) = 0;
-  virtual void UnregisterMediaPlayer(int player_id) = 0;
-};
-
-}  // namespace media
-
-#endif  // MEDIA_BLINK_RENDERER_MEDIA_PLAYER_INTERFACE_H_
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index 4f80415..ddc23ba 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -64,10 +64,6 @@
 #include "third_party/blink/public/web/web_widget.h"
 #include "url/gurl.h"
 
-#if defined(OS_ANDROID)
-#include "media/blink/renderer_media_player_interface.h"
-#endif
-
 using ::testing::_;
 using ::testing::AnyNumber;
 using ::testing::Eq;
diff --git a/media/capture/mojom/video_capture.mojom b/media/capture/mojom/video_capture.mojom
index 6926112..adb9ec3 100644
--- a/media/capture/mojom/video_capture.mojom
+++ b/media/capture/mojom/video_capture.mojom
@@ -108,4 +108,7 @@
   // Get the format(s) in use by a device referenced by |session_id|.
   GetDeviceFormatsInUse(int32 device_id, int32 session_id)
     => (array<VideoCaptureFormat> formats_in_use);
+
+  // Sends a log message to the VideoCaptureHost.
+  OnLog(int32 device_id, string message);
 };
diff --git a/media/capture/video/mock_device.cc b/media/capture/video/mock_device.cc
index 4b0a1a6..080b8a4 100644
--- a/media/capture/video/mock_device.cc
+++ b/media/capture/video/mock_device.cc
@@ -25,6 +25,10 @@
       frame_feedback_id);
 }
 
+void MockDevice::SendOnStarted() {
+  client_->OnStarted();
+}
+
 void MockDevice::AllocateAndStart(const media::VideoCaptureParams& params,
                                   std::unique_ptr<Client> client) {
   client_ = std::move(client);
diff --git a/media/capture/video/mock_device.h b/media/capture/video/mock_device.h
index f205617c..4de03688 100644
--- a/media/capture/video/mock_device.h
+++ b/media/capture/video/mock_device.h
@@ -21,6 +21,7 @@
   void SendStubFrame(const media::VideoCaptureFormat& format,
                      int rotation,
                      int frame_feedback_id);
+  void SendOnStarted();
 
   // media::VideoCaptureDevice implementation.
   MOCK_METHOD2(DoAllocateAndStart,
diff --git a/media/capture/video/mock_device_factory.cc b/media/capture/video/mock_device_factory.cc
index 288c342..cea527f 100644
--- a/media/capture/video/mock_device_factory.cc
+++ b/media/capture/video/mock_device_factory.cc
@@ -57,6 +57,10 @@
   devices_[descriptor] = device;
 }
 
+void MockDeviceFactory::RemoveAllDevices() {
+  devices_.clear();
+}
+
 std::unique_ptr<media::VideoCaptureDevice> MockDeviceFactory::CreateDevice(
     const media::VideoCaptureDeviceDescriptor& device_descriptor) {
   if (devices_.find(device_descriptor) == devices_.end())
diff --git a/media/capture/video/mock_device_factory.h b/media/capture/video/mock_device_factory.h
index 8ca8c06..d98862d 100644
--- a/media/capture/video/mock_device_factory.h
+++ b/media/capture/video/mock_device_factory.h
@@ -21,6 +21,7 @@
 
   void AddMockDevice(media::VideoCaptureDevice* device,
                      const media::VideoCaptureDeviceDescriptor& descriptor);
+  void RemoveAllDevices();
 
   // media::VideoCaptureDeviceFactory implementation.
   std::unique_ptr<media::VideoCaptureDevice> CreateDevice(
diff --git a/media/capture/video/win/video_capture_device_factory_win.cc b/media/capture/video/win/video_capture_device_factory_win.cc
index 85f6559..21f1b71 100644
--- a/media/capture/video/win/video_capture_device_factory_win.cc
+++ b/media/capture/video/win/video_capture_device_factory_win.cc
@@ -85,7 +85,9 @@
     // Elgato HD60 Pro
     "12ab:0380",
     // Sensoray 2253
-    "1943:2253"};
+    "1943:2253",
+    // Dell E5440
+    "0c45:64d0", "0c45:64d2"};
 
 const std::pair<VideoCaptureApi, std::vector<std::pair<GUID, GUID>>>
     kMfAttributes[] = {{VideoCaptureApi::WIN_MEDIA_FOUNDATION,
diff --git a/media/capture/video_capturer_source.h b/media/capture/video_capturer_source.h
index c4cc854..73d32fa 100644
--- a/media/capture/video_capturer_source.h
+++ b/media/capture/video_capturer_source.h
@@ -107,6 +107,9 @@
   // may still occur after this call, so the caller must take care to
   // use refcounted or weak references in |new_frame_callback|.
   virtual void StopCapture() = 0;
+
+  // Sends a log message to the source.
+  virtual void OnLog(const std::string& message) {}
 };
 
 }  // namespace media
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index 59fa650..6544e86 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -126,7 +126,7 @@
       webaudio_attached_(false),
       mono_output_(false),
       fuzzing_(false),
-#if defined(ADDRESS_SANITIZER)
+#if defined(ADDRESS_SANITIZER) || defined(UNDEFINED_SANITIZER)
       disable_run_timeout_(base::TimeDelta()),
 #endif
       pipeline_(
diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h
index e52aac5f..36745ed5 100644
--- a/media/test/pipeline_integration_test_base.h
+++ b/media/test/pipeline_integration_test_base.h
@@ -159,7 +159,7 @@
   bool webaudio_attached_;
   bool mono_output_;
   bool fuzzing_;
-#if defined(ADDRESS_SANITIZER)
+#if defined(ADDRESS_SANITIZER) || defined(UNDEFINED_SANITIZER)
   // TODO(https://crbug.com/924030): ASAN causes Run() timeouts to be reached.
   base::RunLoop::ScopedRunTimeoutForTest disable_run_timeout_;
 #endif
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h
index 052ab391..384214a 100644
--- a/net/quic/quic_flags_list.h
+++ b/net/quic/quic_flags_list.h
@@ -335,3 +335,10 @@
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_log_cert_name_for_empty_sct,
           true)
+
+// If true, close connection with INVALID_STOP_WAITING if received a
+// STOP_WAITING with least_unacked 0.
+QUIC_FLAG(
+    bool,
+    FLAGS_quic_reloadable_flag_quic_close_connection_with_zero_least_unacked_stop_waiting,
+    true)
diff --git a/net/third_party/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc b/net/third_party/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
index 905815a..d88170d 100644
--- a/net/third_party/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
+++ b/net/third_party/quic/core/qpack/fuzzer/qpack_encoder_stream_sender_fuzzer.cc
@@ -22,7 +22,7 @@
   NoOpDelegate() = default;
   ~NoOpDelegate() override = default;
 
-  void Write(QuicStringPiece data) override {}
+  void WriteEncoderStreamData(QuicStringPiece data) override {}
 };
 
 // This fuzzer exercises QpackEncoderStreamSender.
diff --git a/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.cc b/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.cc
index 03fa5cca..36f13ab 100644
--- a/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.cc
+++ b/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.cc
@@ -44,7 +44,7 @@
   return true;
 }
 
-void QpackOfflineDecoder::OnError(QuicStringPiece error_message) {
+void QpackOfflineDecoder::OnEncoderStreamError(QuicStringPiece error_message) {
   QUIC_LOG(ERROR) << "Encoder stream error: " << error_message;
   encoder_stream_error_detected_ = true;
 }
diff --git a/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.h b/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.h
index ac6deb6..240f617 100644
--- a/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.h
+++ b/net/third_party/quic/core/qpack/offline/qpack_offline_decoder.h
@@ -32,7 +32,7 @@
                                   QuicStringPiece expected_headers_filename);
 
   // QpackDecoder::EncoderStreamErrorDelegate implementation:
-  void OnError(QuicStringPiece error_message) override;
+  void OnEncoderStreamError(QuicStringPiece error_message) override;
 
  private:
   // Parse decoder parameters from |input_filename| and set up |decoder_|
diff --git a/net/third_party/quic/core/qpack/qpack_decoder.cc b/net/third_party/quic/core/qpack/qpack_decoder.cc
index 7735b33..c55a4bf 100644
--- a/net/third_party/quic/core/qpack/qpack_decoder.cc
+++ b/net/third_party/quic/core/qpack/qpack_decoder.cc
@@ -42,13 +42,14 @@
   if (is_static) {
     auto entry = header_table_.LookupEntry(/* is_static = */ true, name_index);
     if (!entry) {
-      encoder_stream_error_delegate_->OnError("Invalid static table entry.");
+      encoder_stream_error_delegate_->OnEncoderStreamError(
+          "Invalid static table entry.");
       return;
     }
 
     entry = header_table_.InsertEntry(entry->name(), value);
     if (!entry) {
-      encoder_stream_error_delegate_->OnError(
+      encoder_stream_error_delegate_->OnEncoderStreamError(
           "Error inserting entry with name reference.");
     }
     return;
@@ -56,19 +57,21 @@
 
   uint64_t absolute_index;
   if (!EncoderStreamRelativeIndexToAbsoluteIndex(name_index, &absolute_index)) {
-    encoder_stream_error_delegate_->OnError("Invalid relative index.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Invalid relative index.");
     return;
   }
 
   const QpackEntry* entry =
       header_table_.LookupEntry(/* is_static = */ false, absolute_index);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Dynamic table entry not found.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Dynamic table entry not found.");
     return;
   }
   entry = header_table_.InsertEntry(entry->name(), value);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError(
+    encoder_stream_error_delegate_->OnEncoderStreamError(
         "Error inserting entry with name reference.");
   }
 }
@@ -77,38 +80,42 @@
                                                 QuicStringPiece value) {
   const QpackEntry* entry = header_table_.InsertEntry(name, value);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Error inserting literal entry.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Error inserting literal entry.");
   }
 }
 
 void QpackDecoder::OnDuplicate(uint64_t index) {
   uint64_t absolute_index;
   if (!EncoderStreamRelativeIndexToAbsoluteIndex(index, &absolute_index)) {
-    encoder_stream_error_delegate_->OnError("Invalid relative index.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Invalid relative index.");
     return;
   }
 
   const QpackEntry* entry =
       header_table_.LookupEntry(/* is_static = */ false, absolute_index);
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Dynamic table entry not found.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Dynamic table entry not found.");
     return;
   }
   entry = header_table_.InsertEntry(entry->name(), entry->value());
   if (!entry) {
-    encoder_stream_error_delegate_->OnError("Error inserting duplicate entry.");
+    encoder_stream_error_delegate_->OnEncoderStreamError(
+        "Error inserting duplicate entry.");
   }
 }
 
 void QpackDecoder::OnSetDynamicTableCapacity(uint64_t capacity) {
   if (!header_table_.SetDynamicTableCapacity(capacity)) {
-    encoder_stream_error_delegate_->OnError(
+    encoder_stream_error_delegate_->OnEncoderStreamError(
         "Error updating dynamic table capacity.");
   }
 }
 
 void QpackDecoder::OnErrorDetected(QuicStringPiece error_message) {
-  encoder_stream_error_delegate_->OnError(error_message);
+  encoder_stream_error_delegate_->OnEncoderStreamError(error_message);
 }
 
 bool QpackDecoder::EncoderStreamRelativeIndexToAbsoluteIndex(
diff --git a/net/third_party/quic/core/qpack/qpack_decoder.h b/net/third_party/quic/core/qpack/qpack_decoder.h
index 1816fe0..65474e1 100644
--- a/net/third_party/quic/core/qpack/qpack_decoder.h
+++ b/net/third_party/quic/core/qpack/qpack_decoder.h
@@ -31,7 +31,7 @@
    public:
     virtual ~EncoderStreamErrorDelegate() {}
 
-    virtual void OnError(QuicStringPiece error_message) = 0;
+    virtual void OnEncoderStreamError(QuicStringPiece error_message) = 0;
   };
 
   QpackDecoder(
diff --git a/net/third_party/quic/core/qpack/qpack_decoder_stream_sender.cc b/net/third_party/quic/core/qpack/qpack_decoder_stream_sender.cc
index 9083f0a8..be1c219 100644
--- a/net/third_party/quic/core/qpack/qpack_decoder_stream_sender.cc
+++ b/net/third_party/quic/core/qpack/qpack_decoder_stream_sender.cc
@@ -28,7 +28,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteDecoderStreamData(output);
 }
 
 void QpackDecoderStreamSender::SendHeaderAcknowledgement(
@@ -42,7 +42,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteDecoderStreamData(output);
 }
 
 void QpackDecoderStreamSender::SendStreamCancellation(QuicStreamId stream_id) {
@@ -55,7 +55,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteDecoderStreamData(output);
 }
 
 }  // namespace quic
diff --git a/net/third_party/quic/core/qpack/qpack_decoder_stream_sender.h b/net/third_party/quic/core/qpack/qpack_decoder_stream_sender.h
index d4941cd..600962c2 100644
--- a/net/third_party/quic/core/qpack/qpack_decoder_stream_sender.h
+++ b/net/third_party/quic/core/qpack/qpack_decoder_stream_sender.h
@@ -24,9 +24,10 @@
     virtual ~Delegate() = default;
 
     // Encoded |data| is ready to be written on the decoder stream.
-    // Write() is called exactly once for each instruction, |data| contains the
-    // entire encoded instruction and it is guaranteed to be not empty.
-    virtual void Write(QuicStringPiece data) = 0;
+    // WriteDecoderStreamData() is called exactly once for each instruction.
+    // |data| contains the entire encoded instruction and it is guaranteed to be
+    // not empty.
+    virtual void WriteDecoderStreamData(QuicStringPiece data) = 0;
   };
 
   explicit QpackDecoderStreamSender(Delegate* delegate);
diff --git a/net/third_party/quic/core/qpack/qpack_decoder_stream_sender_test.cc b/net/third_party/quic/core/qpack/qpack_decoder_stream_sender_test.cc
index 68d9f80..f7e9797 100644
--- a/net/third_party/quic/core/qpack/qpack_decoder_stream_sender_test.cc
+++ b/net/third_party/quic/core/qpack/qpack_decoder_stream_sender_test.cc
@@ -20,7 +20,7 @@
  public:
   ~MockSenderDelegate() override = default;
 
-  MOCK_METHOD1(Write, void(QuicStringPiece data));
+  MOCK_METHOD1(WriteDecoderStreamData, void(QuicStringPiece data));
 };
 
 class QpackDecoderStreamSenderTest : public QuicTest {
@@ -33,44 +33,56 @@
 };
 
 TEST_F(QpackDecoderStreamSenderTest, InsertCountIncrement) {
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("00"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("00"))));
   stream_.SendInsertCountIncrement(0);
 
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("0a"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("0a"))));
   stream_.SendInsertCountIncrement(10);
 
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("3f00"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("3f00"))));
   stream_.SendInsertCountIncrement(63);
 
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("3f8901"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("3f8901"))));
   stream_.SendInsertCountIncrement(200);
 }
 
 TEST_F(QpackDecoderStreamSenderTest, HeaderAcknowledgement) {
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("80"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("80"))));
   stream_.SendHeaderAcknowledgement(0);
 
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("a5"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("a5"))));
   stream_.SendHeaderAcknowledgement(37);
 
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("ff00"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("ff00"))));
   stream_.SendHeaderAcknowledgement(127);
 
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("fff802"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("fff802"))));
   stream_.SendHeaderAcknowledgement(503);
 }
 
 TEST_F(QpackDecoderStreamSenderTest, StreamCancellation) {
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("40"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("40"))));
   stream_.SendStreamCancellation(0);
 
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("53"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("53"))));
   stream_.SendStreamCancellation(19);
 
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("7f00"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("7f00"))));
   stream_.SendStreamCancellation(63);
 
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("7f2f"))));
+  EXPECT_CALL(delegate_,
+              WriteDecoderStreamData(Eq(QuicTextUtils::HexDecode("7f2f"))));
   stream_.SendStreamCancellation(110);
 }
 
diff --git a/net/third_party/quic/core/qpack/qpack_decoder_test.cc b/net/third_party/quic/core/qpack/qpack_decoder_test.cc
index f2c9a35..da6c2da 100644
--- a/net/third_party/quic/core/qpack/qpack_decoder_test.cc
+++ b/net/third_party/quic/core/qpack/qpack_decoder_test.cc
@@ -78,7 +78,7 @@
 TEST_P(QpackDecoderTest, EmptyHeaderBlock) {
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("0000"));
 }
@@ -87,7 +87,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("foo")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00002003666f6f"));
 }
@@ -96,7 +96,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f00"));
 }
@@ -105,7 +105,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(""), Eq("")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("00002000"));
 }
@@ -114,7 +114,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode("000023666f6f03626172"));
 }
@@ -125,7 +125,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foobaar"), QuicStringPiece(str)));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000"                // prefix
@@ -184,7 +184,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("custom-key"), Eq("custom-value")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(
       QuicTextUtils::HexDecode("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"));
@@ -195,7 +195,7 @@
       .Times(4);
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000"                        // Prefix.
@@ -269,7 +269,7 @@
 
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0000d1dfccd45f108621e9aec2a11f5c8294e75f000554524143455f1000"));
@@ -312,7 +312,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)))
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
@@ -333,7 +333,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)))
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
@@ -354,7 +354,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("ZZZ"))).InSequence(s);
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq(":method"), Eq("ZZ"))).InSequence(s);
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)))
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)))
       .InSequence(s);
   EXPECT_CALL(handler_, OnDecodingCompleted()).InSequence(s);
 
@@ -376,7 +376,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq("bar")));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
       "0200"   // Required Insert Count 1 and Delta Base 0.
@@ -398,7 +398,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorEntryTooLarge) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Error inserting literal entry.")));
+              OnEncoderStreamError(Eq("Error inserting literal entry.")));
 
   // Set dynamic table capacity to 34.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3f03"));
@@ -408,7 +408,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidStaticTableEntry) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Invalid static table entry.")));
+              OnEncoderStreamError(Eq("Invalid static table entry.")));
 
   // Address invalid static table entry index 99.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("ff2400"));
@@ -416,7 +416,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorInvalidDynamicTableEntry) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Dynamic table entry not found.")));
+              OnEncoderStreamError(Eq("Dynamic table entry not found.")));
 
   DecodeEncoderStreamData(QuicTextUtils::HexDecode(
       "6294e703626172"  // Add literal entry with name "foo" and value "bar".
@@ -427,7 +427,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorDuplicateInvalidEntry) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Dynamic table entry not found.")));
+              OnEncoderStreamError(Eq("Dynamic table entry not found.")));
 
   DecodeEncoderStreamData(QuicTextUtils::HexDecode(
       "6294e703626172"  // Add literal entry with name "foo" and value "bar".
@@ -438,7 +438,7 @@
 
 TEST_P(QpackDecoderTest, EncoderStreamErrorTooLargeInteger) {
   EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Encoded integer too large.")));
+              OnEncoderStreamError(Eq("Encoded integer too large.")));
 
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fffffffffffffffffffff"));
 }
@@ -528,8 +528,9 @@
 }
 
 TEST_P(QpackDecoderTest, TableCapacityMustNotExceedMaximum) {
-  EXPECT_CALL(encoder_stream_error_delegate_,
-              OnError(Eq("Error updating dynamic table capacity.")));
+  EXPECT_CALL(
+      encoder_stream_error_delegate_,
+      OnEncoderStreamError(Eq("Error updating dynamic table capacity.")));
 
   // Try to update dynamic table capacity to 2048, which exceeds the maximum.
   DecodeEncoderStreamData(QuicTextUtils::HexDecode("3fe10f"));
@@ -570,7 +571,7 @@
   EXPECT_CALL(handler_, OnHeaderDecoded(Eq("foo"), Eq(header_value)));
   EXPECT_CALL(handler_, OnDecodingCompleted());
   EXPECT_CALL(decoder_stream_sender_delegate_,
-              Write(Eq(kHeaderAcknowledgement)));
+              WriteDecoderStreamData(Eq(kHeaderAcknowledgement)));
 
   // Send header block with Required Insert Count = 201.
   DecodeHeaderBlock(QuicTextUtils::HexDecode(
diff --git a/net/third_party/quic/core/qpack/qpack_decoder_test_utils.cc b/net/third_party/quic/core/qpack/qpack_decoder_test_utils.cc
index 0c6ba583..5b5a014 100644
--- a/net/third_party/quic/core/qpack/qpack_decoder_test_utils.cc
+++ b/net/third_party/quic/core/qpack/qpack_decoder_test_utils.cc
@@ -13,9 +13,11 @@
 namespace quic {
 namespace test {
 
-void NoopEncoderStreamErrorDelegate::OnError(QuicStringPiece error_message) {}
+void NoopEncoderStreamErrorDelegate::OnEncoderStreamError(
+    QuicStringPiece error_message) {}
 
-void NoopDecoderStreamSenderDelegate::Write(QuicStringPiece data) {}
+void NoopDecoderStreamSenderDelegate::WriteDecoderStreamData(
+    QuicStringPiece data) {}
 
 TestHeadersHandler::TestHeadersHandler()
     : decoding_completed_(false), decoding_error_detected_(false) {}
diff --git a/net/third_party/quic/core/qpack/qpack_decoder_test_utils.h b/net/third_party/quic/core/qpack/qpack_decoder_test_utils.h
index 427fee1..b46b0b4 100644
--- a/net/third_party/quic/core/qpack/qpack_decoder_test_utils.h
+++ b/net/third_party/quic/core/qpack/qpack_decoder_test_utils.h
@@ -21,7 +21,7 @@
  public:
   ~NoopEncoderStreamErrorDelegate() override = default;
 
-  void OnError(QuicStringPiece error_message) override;
+  void OnEncoderStreamError(QuicStringPiece error_message) override;
 };
 
 // Mock QpackDecoder::EncoderStreamErrorDelegate implementation.
@@ -30,7 +30,7 @@
  public:
   ~MockEncoderStreamErrorDelegate() override = default;
 
-  MOCK_METHOD1(OnError, void(QuicStringPiece error_message));
+  MOCK_METHOD1(OnEncoderStreamError, void(QuicStringPiece error_message));
 };
 
 // QpackDecoderStreamSender::Delegate implementation that does nothing.
@@ -39,7 +39,7 @@
  public:
   ~NoopDecoderStreamSenderDelegate() override = default;
 
-  void Write(QuicStringPiece data) override;
+  void WriteDecoderStreamData(QuicStringPiece data) override;
 };
 
 // Mock QpackDecoderStreamSender::Delegate implementation.
@@ -48,7 +48,7 @@
  public:
   ~MockDecoderStreamSenderDelegate() override = default;
 
-  MOCK_METHOD1(Write, void(QuicStringPiece data));
+  MOCK_METHOD1(WriteDecoderStreamData, void(QuicStringPiece data));
 };
 
 // HeadersHandlerInterface implementation that collects decoded headers
diff --git a/net/third_party/quic/core/qpack/qpack_encoder.cc b/net/third_party/quic/core/qpack/qpack_encoder.cc
index ce07d1f..85f79ea 100644
--- a/net/third_party/quic/core/qpack/qpack_encoder.cc
+++ b/net/third_party/quic/core/qpack/qpack_encoder.cc
@@ -48,7 +48,7 @@
 }
 
 void QpackEncoder::OnErrorDetected(QuicStringPiece error_message) {
-  decoder_stream_error_delegate_->OnError(error_message);
+  decoder_stream_error_delegate_->OnDecoderStreamError(error_message);
 }
 
 }  // namespace quic
diff --git a/net/third_party/quic/core/qpack/qpack_encoder.h b/net/third_party/quic/core/qpack/qpack_encoder.h
index 024f558..a3bd150e 100644
--- a/net/third_party/quic/core/qpack/qpack_encoder.h
+++ b/net/third_party/quic/core/qpack/qpack_encoder.h
@@ -36,7 +36,7 @@
    public:
     virtual ~DecoderStreamErrorDelegate() {}
 
-    virtual void OnError(QuicStringPiece error_message) = 0;
+    virtual void OnDecoderStreamError(QuicStringPiece error_message) = 0;
   };
 
   QpackEncoder(
diff --git a/net/third_party/quic/core/qpack/qpack_encoder_stream_sender.cc b/net/third_party/quic/core/qpack/qpack_encoder_stream_sender.cc
index e08538b..d6cdcdd 100644
--- a/net/third_party/quic/core/qpack/qpack_encoder_stream_sender.cc
+++ b/net/third_party/quic/core/qpack/qpack_encoder_stream_sender.cc
@@ -33,7 +33,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
 void QpackEncoderStreamSender::SendInsertWithoutNameReference(
@@ -49,7 +49,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
 void QpackEncoderStreamSender::SendDuplicate(uint64_t index) {
@@ -62,7 +62,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
 void QpackEncoderStreamSender::SendSetDynamicTableCapacity(uint64_t capacity) {
@@ -75,7 +75,7 @@
   instruction_encoder_.Next(std::numeric_limits<size_t>::max(), &output);
   DCHECK(!instruction_encoder_.HasNext());
 
-  delegate_->Write(output);
+  delegate_->WriteEncoderStreamData(output);
 }
 
 }  // namespace quic
diff --git a/net/third_party/quic/core/qpack/qpack_encoder_stream_sender.h b/net/third_party/quic/core/qpack/qpack_encoder_stream_sender.h
index e4afad6d..ecf3150 100644
--- a/net/third_party/quic/core/qpack/qpack_encoder_stream_sender.h
+++ b/net/third_party/quic/core/qpack/qpack_encoder_stream_sender.h
@@ -22,9 +22,10 @@
     virtual ~Delegate() = default;
 
     // Encoded |data| is ready to be written on the encoder stream.
-    // Write() is called exactly once for each instruction, |data| contains the
-    // entire encoded instruction and it is guaranteed to be not empty.
-    virtual void Write(QuicStringPiece data) = 0;
+    // WriteEncoderStreamData() is called exactly once for each instruction.
+    // |data| contains the entire encoded instruction and it is guaranteed to be
+    // not empty.
+    virtual void WriteEncoderStreamData(QuicStringPiece data) = 0;
   };
 
   explicit QpackEncoderStreamSender(Delegate* delegate);
diff --git a/net/third_party/quic/core/qpack/qpack_encoder_stream_sender_test.cc b/net/third_party/quic/core/qpack/qpack_encoder_stream_sender_test.cc
index 316116e4..76215eea 100644
--- a/net/third_party/quic/core/qpack/qpack_encoder_stream_sender_test.cc
+++ b/net/third_party/quic/core/qpack/qpack_encoder_stream_sender_test.cc
@@ -20,7 +20,7 @@
  public:
   ~MockSenderDelegate() override = default;
 
-  MOCK_METHOD1(Write, void(QuicStringPiece data));
+  MOCK_METHOD1(WriteEncoderStreamData, void(QuicStringPiece data));
 };
 
 class QpackEncoderStreamSenderTest : public QuicTest {
@@ -34,22 +34,25 @@
 
 TEST_F(QpackEncoderStreamSenderTest, InsertWithNameReference) {
   // Static, index fits in prefix, empty value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("c500"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("c500"))));
   stream_.SendInsertWithNameReference(true, 5, "");
 
   // Static, index fits in prefix, Huffman encoded value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("c28294e7"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("c28294e7"))));
   stream_.SendInsertWithNameReference(true, 2, "foo");
 
   // Not static, index does not fit in prefix, not Huffman encoded value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("bf4a03626172"))));
+  EXPECT_CALL(delegate_, WriteEncoderStreamData(
+                             Eq(QuicTextUtils::HexDecode("bf4a03626172"))));
   stream_.SendInsertWithNameReference(false, 137, "bar");
 
   // Value length does not fit in prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
   EXPECT_CALL(
       delegate_,
-      Write(Eq(QuicTextUtils::HexDecode(
+      WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode(
           "aa7f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
@@ -59,23 +62,25 @@
 
 TEST_F(QpackEncoderStreamSenderTest, InsertWithoutNameReference) {
   // Empty name and value.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("4000"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("4000"))));
   stream_.SendInsertWithoutNameReference("", "");
 
   // Huffman encoded short strings.
-  EXPECT_CALL(delegate_,
-              Write(Eq(QuicTextUtils::HexDecode("4362617203626172"))));
+  EXPECT_CALL(delegate_, WriteEncoderStreamData(
+                             Eq(QuicTextUtils::HexDecode("4362617203626172"))));
   stream_.SendInsertWithoutNameReference("bar", "bar");
 
   // Not Huffman encoded short strings.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("6294e78294e7"))));
+  EXPECT_CALL(delegate_, WriteEncoderStreamData(
+                             Eq(QuicTextUtils::HexDecode("6294e78294e7"))));
   stream_.SendInsertWithoutNameReference("foo", "foo");
 
   // Not Huffman encoded long strings; length does not fit on prefix.
   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
   EXPECT_CALL(
       delegate_,
-      Write(Eq(QuicTextUtils::HexDecode(
+      WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode(
           "5f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a7f"
           "005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
           "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
@@ -87,21 +92,25 @@
 
 TEST_F(QpackEncoderStreamSenderTest, Duplicate) {
   // Small index fits in prefix.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("11"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("11"))));
   stream_.SendDuplicate(17);
 
   // Large index requires two extension bytes.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("1fd503"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("1fd503"))));
   stream_.SendDuplicate(500);
 }
 
 TEST_F(QpackEncoderStreamSenderTest, SetDynamicTableCapacity) {
   // Small capacity fits in prefix.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("31"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("31"))));
   stream_.SendSetDynamicTableCapacity(17);
 
   // Large capacity requires two extension bytes.
-  EXPECT_CALL(delegate_, Write(Eq(QuicTextUtils::HexDecode("3fd503"))));
+  EXPECT_CALL(delegate_,
+              WriteEncoderStreamData(Eq(QuicTextUtils::HexDecode("3fd503"))));
   stream_.SendSetDynamicTableCapacity(500);
 }
 
diff --git a/net/third_party/quic/core/qpack/qpack_encoder_test.cc b/net/third_party/quic/core/qpack/qpack_encoder_test.cc
index c2b6ec0..392cea8 100644
--- a/net/third_party/quic/core/qpack/qpack_encoder_test.cc
+++ b/net/third_party/quic/core/qpack/qpack_encoder_test.cc
@@ -154,7 +154,7 @@
 
 TEST_P(QpackEncoderTest, DecoderStreamError) {
   EXPECT_CALL(decoder_stream_error_delegate_,
-              OnError(Eq("Encoded integer too large.")));
+              OnDecoderStreamError(Eq("Encoded integer too large.")));
 
   QpackEncoder encoder(&decoder_stream_error_delegate_,
                        &encoder_stream_sender_delegate_);
diff --git a/net/third_party/quic/core/qpack/qpack_encoder_test_utils.cc b/net/third_party/quic/core/qpack/qpack_encoder_test_utils.cc
index e95adbf..4bc13ac 100644
--- a/net/third_party/quic/core/qpack/qpack_encoder_test_utils.cc
+++ b/net/third_party/quic/core/qpack/qpack_encoder_test_utils.cc
@@ -9,9 +9,11 @@
 namespace quic {
 namespace test {
 
-void NoopDecoderStreamErrorDelegate::OnError(QuicStringPiece error_message) {}
+void NoopDecoderStreamErrorDelegate::OnDecoderStreamError(
+    QuicStringPiece error_message) {}
 
-void NoopEncoderStreamSenderDelegate::Write(QuicStringPiece data) {}
+void NoopEncoderStreamSenderDelegate::WriteEncoderStreamData(
+    QuicStringPiece data) {}
 
 QuicString QpackEncode(
     QpackEncoder::DecoderStreamErrorDelegate* decoder_stream_error_delegate,
diff --git a/net/third_party/quic/core/qpack/qpack_encoder_test_utils.h b/net/third_party/quic/core/qpack/qpack_encoder_test_utils.h
index 1442aae..8c8d8ca6 100644
--- a/net/third_party/quic/core/qpack/qpack_encoder_test_utils.h
+++ b/net/third_party/quic/core/qpack/qpack_encoder_test_utils.h
@@ -21,7 +21,7 @@
  public:
   ~NoopDecoderStreamErrorDelegate() override = default;
 
-  void OnError(QuicStringPiece error_message) override;
+  void OnDecoderStreamError(QuicStringPiece error_message) override;
 };
 
 // Mock QpackEncoder::DecoderStreamErrorDelegate implementation.
@@ -30,7 +30,7 @@
  public:
   ~MockDecoderStreamErrorDelegate() override = default;
 
-  MOCK_METHOD1(OnError, void(QuicStringPiece error_message));
+  MOCK_METHOD1(OnDecoderStreamError, void(QuicStringPiece error_message));
 };
 
 // QpackEncoderStreamSender::Delegate implementation that does nothing.
@@ -39,7 +39,7 @@
  public:
   ~NoopEncoderStreamSenderDelegate() override = default;
 
-  void Write(QuicStringPiece data) override;
+  void WriteEncoderStreamData(QuicStringPiece data) override;
 };
 
 QuicString QpackEncode(
diff --git a/net/third_party/quic/core/quic_framer.cc b/net/third_party/quic/core/quic_framer.cc
index 35801a5..d24ce42 100644
--- a/net/third_party/quic/core/quic_framer.cc
+++ b/net/third_party/quic/core/quic_framer.cc
@@ -3268,7 +3268,10 @@
     set_detailed_error("Unable to read least unacked delta.");
     return false;
   }
-  if (header.packet_number.ToUint64() < least_unacked_delta) {
+  if (header.packet_number.ToUint64() < least_unacked_delta ||
+      (GetQuicReloadableFlag(
+           quic_close_connection_with_zero_least_unacked_stop_waiting) &&
+       header.packet_number.ToUint64() == least_unacked_delta)) {
     set_detailed_error("Invalid unacked delta.");
     return false;
   }
diff --git a/remoting/host/win/BUILD.gn b/remoting/host/win/BUILD.gn
index 79dabc14..a557993 100644
--- a/remoting/host/win/BUILD.gn
+++ b/remoting/host/win/BUILD.gn
@@ -161,12 +161,12 @@
 
   deps = [
     "//ipc",
-    "//remoting/host",
+    "//remoting/host:common",
     "//remoting/host:test_support",
     "//remoting/host/it2me:common",
     "//remoting/host/native_messaging",
     "//remoting/host/security_key:unit_tests",
-    "//remoting/host/setup",
+    "//remoting/host/setup:common",
     "//remoting/proto",
     "//remoting/resources",
     "//skia",
diff --git a/services/device/hid/test_report_descriptors.cc b/services/device/hid/test_report_descriptors.cc
index 0ba7a09..0234145 100644
--- a/services/device/hid/test_report_descriptors.cc
+++ b/services/device/hid/test_report_descriptors.cc
@@ -26,10 +26,10 @@
     0x26, 0xe0, 0x2e,  //   Logical Maximum (12000)
     0x35, 0x00,        //   Physical Minimum (0)
     0x45, 0x0c,        //   Physical Maximum (12)
-    0x65, 0x13,        //   Unit (19)
+    0x65, 0x13,        //   Unit (Inch)
     0x55, 0x00,        //   Unit Exponent (0)
     0xa4,              //   Push
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x05, 0x0d,        //   Usage Page (Digitizer)
     0x09, 0x32,        //   Usage (0x32)
     0x09, 0x44,        //   Usage (0x44)
@@ -41,10 +41,10 @@
     0x75, 0x01,        //   Report Size (1)
     0x95, 0x03,        //   Report Count (3)
     0x65, 0x00,        //   Unit (0)
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x01,        //   Report Count (1)
     0x75, 0x05,        //   Report Size (5)
-    0x81, 0x03,        //   Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x03,        //   Input (Con|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xc0,              //  End Collection
     0x85, 0x02,        //  Report ID (0x2)
     0x09, 0x20,        //  Usage (0x20)
@@ -53,7 +53,7 @@
     0xa4,              //   Push
     0x09, 0x30,        //   Usage (0x30)
     0x09, 0x31,        //   Usage (0x31)
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x05, 0x0d,        //   Usage Page (Digitizer)
     0x09, 0x32,        //   Usage (0x32)
     0x15, 0x00,        //   Logical Minimum (0)
@@ -62,15 +62,15 @@
     0x45, 0x01,        //   Physical Maximum (1)
     0x65, 0x00,        //   Unit (0)
     0x75, 0x01,        //   Report Size (1)
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x05, 0x09,        //   Usage Page (Button)
     0x19, 0x00,        //   Usage Minimum (0)
     0x29, 0x10,        //   Usage Maximum (16)
     0x25, 0x10,        //   Logical Maximum (16)
     0x75, 0x05,        //   Report Size (5)
-    0x81, 0x40,        //   Input (Dat|Var|Rel|NoWrp|Lin|Prf|Null|BitF)
+    0x81, 0x40,        //   Input (Dat|Arr|Abs|NoWrp|Lin|Prf|Null|BitF)
     0x75, 0x02,        //   Report Size (2)
-    0x81, 0x01,        //   Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x01,        //   Input (Con|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xc0,              //  End Collection
     0x85, 0x03,        //  Report ID (0x3)
     0x05, 0x0d,        //  Usage Page (Digitizer)
@@ -79,7 +79,7 @@
     0xb4,              //   Pop
     0x09, 0x30,        //   Usage (0x30)
     0x09, 0x31,        //   Usage (0x31)
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x05, 0x0d,        //   Usage Page (Digitizer)
     0x09, 0x32,        //   Usage (0x32)
     0x09, 0x44,        //   Usage (0x44)
@@ -89,20 +89,20 @@
     0x35, 0x00,        //   Physical Minimum (0)
     0x45, 0x01,        //   Physical Maximum (1)
     0x65, 0x00,        //   Unit (0)
-    0x81, 0x02,        //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,        //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x06,        //   Report Count (6)
-    0x81, 0x03,        //   Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x03,        //   Input (Con|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x09, 0x30,        //   Usage (0x30)
     0x15, 0x00,        //   Logical Minimum (0)
     0x25, 0x7f,        //   Logical Maximum (127)
     0x35, 0x00,        //   Physical Minimum (0)
     0x45, 0x2d,        //   Physical Maximum (45)
-    0x67, 0x11, 0xe1,  //   Unit (57617)
+    0x67, 0x11, 0xe1,  //   Unit (Newtons)
     0x00, 0x00,        //   Default
     0x55, 0x04,        //   Unit Exponent (4)
     0x75, 0x08,        //   Report Size (8)
     0x95, 0x01,        //   Report Count (1)
-    0x81, 0x12,        //   Input (Dat|Arr|Rel|NoWrp|NoLin|Prf|NoNull|BitF)
+    0x81, 0x12,        //   Input (Dat|Var|Abs|NoWrp|NoLin|Prf|NoNull|BitF)
     0xc0,              //  End Collection
     0xc0               // End Collection
 };
@@ -121,19 +121,19 @@
     0x25, 0x01,  //  Logical Maximum (1)
     0x75, 0x01,  //  Report Size (1)
     0x95, 0x08,  //  Report Count (8)
-    0x81, 0x02,  //  Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,  //  Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x01,  //  Report Count (1)
     0x75, 0x08,  //  Report Size (8)
-    0x81, 0x03,  //  Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x03,  //  Input (Con|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x05,  //  Report Count (5)
     0x75, 0x01,  //  Report Size (1)
     0x05, 0x08,  //  Usage Page (Led)
     0x19, 0x01,  //  Usage Minimum (1)
     0x29, 0x05,  //  Usage Maximum (5)
-    0x91, 0x02,  //  Output (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x02,  //  Output (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x01,  //  Report Count (1)
     0x75, 0x03,  //  Report Size (3)
-    0x91, 0x03,  //  Output (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x03,  //  Output (Con|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x06,  //  Report Count (6)
     0x75, 0x08,  //  Report Size (8)
     0x15, 0x00,  //  Logical Minimum (0)
@@ -141,7 +141,7 @@
     0x05, 0x07,  //  Usage Page (Keyboard)
     0x19, 0x00,  //  Usage Minimum (0)
     0x29, 0x65,  //  Usage Maximum (101)
-    0x81, 0x00,  //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x00,  //  Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xc0         // End Collection
 };
 const size_t kKeyboardSize = base::size(kKeyboard);
@@ -158,11 +158,11 @@
     0x75, 0x08,        //  Report Size (8)
     0x95, 0x80,        //  Report Count (128)
     0x09, 0x02,        //  Usage (0x2)
-    0xb2, 0x02, 0x01,  //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|Buff)
+    0xb2, 0x02, 0x01,  //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|Buff)
     0x85, 0x02,        //  Report ID (0x2)
     0x95, 0xf3,        //  Report Count (243)
     0x09, 0x03,        //  Usage (0x3)
-    0xb2, 0x02, 0x01,  //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|Buff)
+    0xb2, 0x02, 0x01,  //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|Buff)
     0x85, 0x03,        //  Report ID (0x3)
     0x05, 0x82,        //  Usage Page (Monitor 2)
     0x67, 0xE1, 0x00,  //  Unit (System: SI, Lum. Intensity: Candela)
@@ -172,11 +172,11 @@
     0x75, 0x10,        //  Report Size (16)
     0x26, 0xc8, 0x00,  //  Logical Maximum (200)
     0x09, 0x10,        //  Usage (0x10)
-    0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0xb1, 0x02,        //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x85, 0x04,        //  Report ID (0x4)
     0x25, 0x64,        //  Logical Maximum (100)
     0x09, 0x12,        //  Usage (0x12)
-    0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0xb1, 0x02,        //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x06,        //  Report Count (6)
     0x26, 0xff, 0x00,  //  Logical Maximum (255)
     0x09, 0x16,        //  Usage (0x16)
@@ -185,7 +185,7 @@
     0x09, 0x6c,        //  Usage (0x6C)
     0x09, 0x6e,        //  Usage (0x6E)
     0x09, 0x70,        //  Usage (0x70)
-    0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0xb1, 0x02,        //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x85, 0x05,        //  Report ID (0x5)
     0x25, 0x7f,        //  Logical Maximum (127)
     0x09, 0x20,        //  Usage (0x20)
@@ -194,7 +194,7 @@
     0x09, 0x32,        //  Usage (0x32)
     0x09, 0x42,        //  Usage (0x42)
     0x09, 0x44,        //  Usage (0x44)
-    0xb1, 0x02,        //  Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0xb1, 0x02,        //  Feature (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xc0               // End Collection
 };
 const size_t kMonitorSize = base::size(kMonitor);
@@ -214,10 +214,10 @@
     0x25, 0x01,  //   Logical Maximum (1)
     0x95, 0x03,  //   Report Count (3)
     0x75, 0x01,  //   Report Size (1)
-    0x81, 0x02,  //   Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x02,  //   Input (Dat|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x95, 0x01,  //   Report Count (1)
     0x75, 0x05,  //   Report Size (5)
-    0x81, 0x03,  //   Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x03,  //   Input (Con|Var|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x05, 0x01,  //   Usage Page (Generic Desktop)
     0x09, 0x30,  //   Usage (0x30)
     0x09, 0x31,  //   Usage (0x31)
@@ -225,7 +225,7 @@
     0x25, 0x7f,  //   Logical Maximum (127)
     0x75, 0x08,  //   Report Size (8)
     0x95, 0x02,  //   Report Count (2)
-    0x81, 0x06,  //   Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x06,  //   Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
     0xc0,        //  End Collection
     0xc0         // End Collection
 };
@@ -242,9 +242,9 @@
     0x15, 0x00,        //  Logical Minimum (0)
     0x26, 0xFF, 0x00,  //  Logical Maximum (255)
     0x09, 0x01,        //  Usage (0x1)
-    0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x00,        //  Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x09, 0x01,        //  Usage (0x1)
-    0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x00,        //  Output (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xC0,              // End Collection
     0x06, 0x00, 0xFF,  // Usage Page (Vendor)
     0x09, 0x02,        // Usage (0x2)
@@ -255,9 +255,9 @@
     0x15, 0x00,        //  Logical Minimum (0)
     0x26, 0xFF, 0x00,  //  Logical Maximum (255)
     0x09, 0x02,        //  Usage (0x2)
-    0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x00,        //  Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x09, 0x02,        //  Usage (0x2)
-    0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x00,        //  Output (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xC0,              // End Collection
     0x06, 0x00, 0xFF,  // Usage Page (Vendor)
     0x09, 0x04,        // Usage (0x4)
@@ -268,17 +268,17 @@
     0x15, 0x00,        //  Logical Minimum (0)
     0x26, 0xFF, 0x00,  //  Logical Maximum (255)
     0x09, 0x41,        //  Usage (0x41)
-    0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x00,        //  Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x09, 0x41,        //  Usage (0x41)
-    0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x00,        //  Output (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x85, 0x21,        //  Report ID (0x21)
     0x95, 0x1F,        //  Report Count (31)
     0x15, 0x00,        //  Logical Minimum (0)
     0x26, 0xFF, 0x00,  //  Logical Maximum (255)
     0x09, 0x42,        //  Usage (0x42)
-    0x81, 0x00,        //  Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x81, 0x00,        //  Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0x09, 0x42,        //  Usage (0x42)
-    0x91, 0x00,        //  Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+    0x91, 0x00,        //  Output (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
     0xC0               // End Collection
 };
 const size_t kLogitechUnifyingReceiverSize =
@@ -288,8 +288,8 @@
 const uint8_t kSonyDualshock3[] = {
     0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
     0x09, 0x04,        // Usage (Joystick)
-    0xA1, 0x01,        // Collection (Physical)
-    0xA1, 0x02,        //   Collection (Application)
+    0xA1, 0x01,        // Collection (Application)
+    0xA1, 0x02,        //   Collection (Logical)
     0x85, 0x01,        //     Report ID (1)
     0x75, 0x08,        //     Report Size (8)
     0x95, 0x01,        //     Report Count (1)
@@ -318,7 +318,7 @@
     0x26, 0xFF, 0x00,  //     Logical Maximum (255)
     0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
     0x09, 0x01,        //     Usage (Pointer)
-    0xA1, 0x00,        //     Collection (Undefined)
+    0xA1, 0x00,        //     Collection (Physical)
     0x75, 0x08,        //       Report Size (8)
     0x95, 0x04,        //       Report Count (4)
     0x35, 0x00,        //       Physical Minimum (0)
@@ -347,7 +347,7 @@
     0xB1, 0x02,        //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred
                        //     State,No Null Position,Non-volatile)
     0xC0,              //   End Collection
-    0xA1, 0x02,        //   Collection (Application)
+    0xA1, 0x02,        //   Collection (Logical)
     0x85, 0x02,        //     Report ID (2)
     0x75, 0x08,        //     Report Size (8)
     0x95, 0x30,        //     Report Count (48)
@@ -355,7 +355,7 @@
     0xB1, 0x02,        //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred
                        //     State,No Null Position,Non-volatile)
     0xC0,              //   End Collection
-    0xA1, 0x02,        //   Collection (Application)
+    0xA1, 0x02,        //   Collection (Logical)
     0x85, 0xEE,        //     Report ID (238)
     0x75, 0x08,        //     Report Size (8)
     0x95, 0x30,        //     Report Count (48)
@@ -363,7 +363,7 @@
     0xB1, 0x02,        //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred
                        //     State,No Null Position,Non-volatile)
     0xC0,              //   End Collection
-    0xA1, 0x02,        //   Collection (Application)
+    0xA1, 0x02,        //   Collection (Logical)
     0x85, 0xEF,        //     Report ID (239)
     0x75, 0x08,        //     Report Size (8)
     0x95, 0x30,        //     Report Count (48)
@@ -1642,4 +1642,328 @@
 const size_t kMicrosoftXboxAdaptiveControllerSize =
     base::size(kMicrosoftXboxAdaptiveController);
 
+const uint8_t kNexusPlayerController[] = {
+    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x05,        // Usage (Game Pad)
+    0xA1, 0x01,        // Collection (Application)
+    0x85, 0x01,        //   Report ID (1)
+    0x05, 0x09,        //   Usage Page (Button)
+    0x0A, 0x01, 0x00,  //   Usage (0x01)
+    0x0A, 0x02, 0x00,  //   Usage (0x02)
+    0x0A, 0x04, 0x00,  //   Usage (0x04)
+    0x0A, 0x05, 0x00,  //   Usage (0x05)
+    0x0A, 0x07, 0x00,  //   Usage (0x07)
+    0x0A, 0x08, 0x00,  //   Usage (0x08)
+    0x0A, 0x0E, 0x00,  //   Usage (0x0E)
+    0x0A, 0x0F, 0x00,  //   Usage (0x0F)
+    0x0A, 0x0D, 0x00,  //   Usage (0x0D)
+    0x05, 0x0C,        //   Usage Page (Consumer)
+    0x0A, 0x24, 0x02,  //   Usage (AC Back)
+    0x0A, 0x23, 0x02,  //   Usage (AC Home)
+    0x15, 0x00,        //   Logical Minimum (0)
+    0x25, 0x01,        //   Logical Maximum (1)
+    0x75, 0x01,        //   Report Size (1)
+    0x95, 0x0B,        //   Report Count (11)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x75, 0x01,        //   Report Size (1)
+    0x95, 0x01,        //   Report Count (1)
+    0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
+    0x75, 0x04,        //   Report Size (4)
+    0x95, 0x01,        //   Report Count (1)
+    0x25, 0x07,        //   Logical Maximum (7)
+    0x46, 0x3B, 0x01,  //   Physical Maximum (315)
+    0x66, 0x14, 0x00,  //   Unit (System: English Rotation, Length: Centimeter)
+    0x09, 0x39,        //   Usage (Hat switch)
+    0x81, 0x42,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   Null State)
+    0x66, 0x00, 0x00,  //   Unit (None)
+    0xA1, 0x00,        //   Collection (Physical)
+    0x09, 0x30,        //     Usage (X)
+    0x09, 0x31,        //     Usage (Y)
+    0x09, 0x32,        //     Usage (Z)
+    0x09, 0x35,        //     Usage (Rz)
+    0x05, 0x02,        //     Usage Page (Sim Ctrls)
+    0x09, 0xC5,        //     Usage (Brake)
+    0x09, 0xC4,        //     Usage (Accelerator)
+    0x15, 0x00,        //     Logical Minimum (0)
+    0x26, 0xFF, 0x00,  //     Logical Maximum (255)
+    0x35, 0x00,        //     Physical Minimum (0)
+    0x46, 0xFF, 0x00,  //     Physical Maximum (255)
+    0x75, 0x08,        //     Report Size (8)
+    0x95, 0x06,        //     Report Count (6)
+    0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred
+                       //     State,No Null Position)
+    0xC0,              //   End Collection
+    0x85, 0x02,        //   Report ID (2)
+    0x05, 0x08,        //   Usage Page (LEDs)
+    0x0A, 0x01, 0x00,  //   Usage (Num Lock)
+    0x0A, 0x02, 0x00,  //   Usage (Caps Lock)
+    0x0A, 0x03, 0x00,  //   Usage (Scroll Lock)
+    0x0A, 0x04, 0x00,  //   Usage (Compose)
+    0x15, 0x00,        //   Logical Minimum (0)
+    0x25, 0x01,        //   Logical Maximum (1)
+    0x75, 0x01,        //   Report Size (1)
+    0x95, 0x04,        //   Report Count (4)
+    0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position,Non-volatile)
+    0x75, 0x04,        //   Report Size (4)
+    0x95, 0x01,        //   Report Count (1)
+    0x91, 0x03,        //   Output (Const,Var,Abs,No Wrap,Linear,Preferred
+                       //   State,No Null Position,Non-volatile)
+    0xC0,              // End Collection
+    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x05,        // Usage (Game Pad)
+    0xA1, 0x01,        // Collection (Application)
+    0x85, 0x03,        //   Report ID (3)
+    0x05, 0x06,        //   Usage Page (Generic Dev Ctrls)
+    0x09, 0x20,        //   Usage (Battery Strength)
+    0x15, 0x00,        //   Logical Minimum (0)
+    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+    0x75, 0x08,        //   Report Size (8)
+    0x95, 0x01,        //   Report Count (1)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x06, 0xBC, 0xFF,  //   Usage Page (Vendor Defined 0xFFBC)
+    0x0A, 0xAD, 0xBD,  //   Usage (0xBDAD)
+    0x75, 0x08,        //   Report Size (8)
+    0x95, 0x06,        //   Report Count (6)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0xC0,              // End Collection
+    0x00,              // Unknown (bTag: 0x00, bType: 0x00)
+};
+const size_t kNexusPlayerControllerSize = base::size(kNexusPlayerController);
+
+const uint8_t kSteamControllerKeyboard[] = {
+    0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x06,  // Usage (Keyboard)
+    0x95, 0x01,  // Report Count (1)
+    0xA1, 0x01,  // Collection (Application)
+    0x05, 0x07,  //   Usage Page (Kbrd/Keypad)
+    0x19, 0xE0,  //   Usage Minimum (0xE0)
+    0x29, 0xE7,  //   Usage Maximum (0xE7)
+    0x15, 0x00,  //   Logical Minimum (0)
+    0x25, 0x01,  //   Logical Maximum (1)
+    0x75, 0x01,  //   Report Size (1)
+    0x95, 0x08,  //   Report Count (8)
+    0x81, 0x02,  //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                 //   No Null Position)
+    0x95, 0x01,  //   Report Count (1)
+    0x75, 0x08,  //   Report Size (8)
+    0x81, 0x01,  //   Input (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //   State,No Null Position)
+    0x95, 0x05,  //   Report Count (5)
+    0x75, 0x01,  //   Report Size (1)
+    0x05, 0x08,  //   Usage Page (LEDs)
+    0x19, 0x01,  //   Usage Minimum (Num Lock)
+    0x29, 0x05,  //   Usage Maximum (Kana)
+    0x91, 0x02,  //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                 //   No Null Position,Non-volatile)
+    0x95, 0x01,  //   Report Count (1)
+    0x75, 0x03,  //   Report Size (3)
+    0x91, 0x01,  //   Output (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //   State,No Null Position,Non-volatile)
+    0x95, 0x06,  //   Report Count (6)
+    0x75, 0x08,  //   Report Size (8)
+    0x15, 0x00,  //   Logical Minimum (0)
+    0x25, 0x65,  //   Logical Maximum (101)
+    0x05, 0x07,  //   Usage Page (Kbrd/Keypad)
+    0x19, 0x00,  //   Usage Minimum (0x00)
+    0x29, 0x65,  //   Usage Maximum (0x65)
+    0x81, 0x00,  //   Input (Data,Array,Abs,No Wrap,Linear,Preferred
+                 //   State,No Null Position)
+    0xC0,        // End Collection
+};
+const size_t kSteamControllerKeyboardSize =
+    base::size(kSteamControllerKeyboard);
+
+const uint8_t kSteamControllerMouse[] = {
+    0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x02,  // Usage (Mouse)
+    0xA1, 0x01,  // Collection (Application)
+    0x09, 0x01,  //   Usage (Pointer)
+    0xA1, 0x00,  //   Collection (Physical)
+    0x05, 0x09,  //     Usage Page (Button)
+    0x19, 0x01,  //     Usage Minimum (0x01)
+    0x29, 0x05,  //     Usage Maximum (0x05)
+    0x15, 0x00,  //     Logical Minimum (0)
+    0x25, 0x01,  //     Logical Maximum (1)
+    0x95, 0x05,  //     Report Count (5)
+    0x75, 0x01,  //     Report Size (1)
+    0x81, 0x02,  //     Input (Data,Var,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0x95, 0x01,  //     Report Count (1)
+    0x75, 0x03,  //     Report Size (3)
+    0x81, 0x01,  //     Input (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0x05, 0x01,  //     Usage Page (Generic Desktop Ctrls)
+    0x09, 0x30,  //     Usage (X)
+    0x09, 0x31,  //     Usage (Y)
+    0x09, 0x38,  //     Usage (Wheel)
+    0x15, 0x81,  //     Logical Minimum (-127)
+    0x25, 0x7F,  //     Logical Maximum (127)
+    0x75, 0x08,  //     Report Size (8)
+    0x95, 0x03,  //     Report Count (3)
+    0x81, 0x06,  //     Input (Data,Var,Rel,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0xC0,        //   End Collection
+    0xC0,        // End Collection
+};
+const size_t kSteamControllerMouseSize = base::size(kSteamControllerMouse);
+
+const uint8_t kSteamControllerVendor[] = {
+    0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
+    0x09, 0x01,        // Usage (0x01)
+    0xA1, 0x01,        // Collection (Application)
+    0x15, 0x00,        //   Logical Minimum (0)
+    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+    0x75, 0x08,        //   Report Size (8)
+    0x95, 0x40,        //   Report Count (64)
+    0x09, 0x01,        //   Usage (0x01)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x95, 0x40,        //   Report Count (64)
+    0x09, 0x01,        //   Usage (0x01)
+    0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position,Non-volatile)
+    0x95, 0x40,        //   Report Count (64)
+    0x09, 0x01,        //   Usage (0x01)
+    0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred
+                       //   State,No Null Position,Non-volatile)
+    0xC0,              // End Collection
+};
+const size_t kSteamControllerVendorSize = base::size(kSteamControllerVendor);
+
+const uint8_t kXSkillsUsbAdapter[] = {
+    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x04,        // Usage (Joystick)
+    0xA1, 0x01,        // Collection (Application)
+    0x05, 0x09,        //   Usage Page (Button)
+    0x19, 0x01,        //   Usage Minimum (0x01)
+    0x29, 0x0C,        //   Usage Maximum (0x0C)
+    0x15, 0x00,        //   Logical Minimum (0)
+    0x25, 0x01,        //   Logical Maximum (1)
+    0x35, 0x00,        //   Physical Minimum (0)
+    0x45, 0x01,        //   Physical Maximum (1)
+    0x75, 0x01,        //   Report Size (1)
+    0x95, 0x0C,        //   Report Count (12)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x95, 0x04,        //   Report Count (4)
+    0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
+    0x09, 0x30,        //   Usage (X)
+    0x09, 0x31,        //   Usage (Y)
+    0x09, 0x35,        //   Usage (Rz)
+    0x09, 0x32,        //   Usage (Z)
+    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+    0x46, 0xFF, 0x00,  //   Physical Maximum (255)
+    0x66, 0x00, 0x00,  //   Unit (None)
+    0x75, 0x08,        //   Report Size (8)
+    0x95, 0x04,        //   Report Count (4)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x09, 0x33,        //   Usage (Rx)
+    0x09, 0x34,        //   Usage (Ry)
+    0x26, 0x0F, 0x00,  //   Logical Maximum (15)
+    0x46, 0x0F, 0x00,  //   Physical Maximum (15)
+    0x75, 0x04,        //   Report Size (4)
+    0x95, 0x02,        //   Report Count (2)
+    0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position)
+    0x75, 0x08,        //   Report Size (8)
+    0x06, 0x00, 0xFF,  //   Usage Page (Vendor Defined 0xFF00)
+    0x19, 0x01,        //   Usage Minimum (0x01)
+    0x29, 0x04,        //   Usage Maximum (0x04)
+    0x95, 0x04,        //   Report Count (4)
+    0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                       //   No Null Position,Non-volatile)
+    0xC0,              // End Collection
+};
+const size_t kXSkillsUsbAdapterSize = base::size(kXSkillsUsbAdapter);
+
+const uint8_t kBelkinNostromoKeyboard[] = {
+    0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x06,  // Usage (Keyboard)
+    0xA1, 0x01,  // Collection (Application)
+    0x05, 0x07,  //   Usage Page (Kbrd/Keypad)
+    0x19, 0xE0,  //   Usage Minimum (0xE0)
+    0x29, 0xE7,  //   Usage Maximum (0xE7)
+    0x15, 0x00,  //   Logical Minimum (0)
+    0x25, 0x01,  //   Logical Maximum (1)
+    0x75, 0x01,  //   Report Size (1)
+    0x95, 0x08,  //   Report Count (8)
+    0x81, 0x02,  //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,
+                 //   No Null Position)
+    0x95, 0x01,  //   Report Count (1)
+    0x75, 0x08,  //   Report Size (8)
+    0x81, 0x01,  //   Input (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //   State,No Null Position)
+    0x95, 0x06,  //   Report Count (6)
+    0x75, 0x08,  //   Report Size (8)
+    0x15, 0x00,  //   Logical Minimum (0)
+    0x25, 0x65,  //   Logical Maximum (101)
+    0x05, 0x07,  //   Usage Page (Kbrd/Keypad)
+    0x19, 0x00,  //   Usage Minimum (0x00)
+    0x29, 0x65,  //   Usage Maximum (0x65)
+    0x81, 0x00,  //   Input (Data,Array,Abs,No Wrap,Linear,Preferred
+                 //   State,No Null Position)
+    0xC0,        // End Collection
+};
+const size_t kBelkinNostromoKeyboardSize = base::size(kBelkinNostromoKeyboard);
+
+const uint8_t kBelkinNostromoMouseAndExtra[] = {
+    0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
+    0x09, 0x02,  // Usage (Mouse)
+    0xA1, 0x01,  // Collection (Application)
+    0x09, 0x01,  //   Usage (Pointer)
+    0xA1, 0x00,  //   Collection (Physical)
+    0x05, 0x09,  //     Usage Page (Button)
+    0x19, 0x01,  //     Usage Minimum (0x01)
+    0x29, 0x03,  //     Usage Maximum (0x03)
+    0x15, 0x00,  //     Logical Minimum (0)
+    0x25, 0x01,  //     Logical Maximum (1)
+    0x95, 0x03,  //     Report Count (3)
+    0x75, 0x01,  //     Report Size (1)
+    0x81, 0x02,  //     Input (Data,Var,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0x95, 0x01,  //     Report Count (1)
+    0x75, 0x05,  //     Report Size (5)
+    0x81, 0x01,  //     Input (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0x05, 0x01,  //     Usage Page (Generic Desktop Ctrls)
+    0x09, 0x30,  //     Usage (X)
+    0x09, 0x31,  //     Usage (Y)
+    0x09, 0x38,  //     Usage (Wheel)
+    0x15, 0x81,  //     Logical Minimum (-127)
+    0x25, 0x7F,  //     Logical Maximum (127)
+    0x75, 0x08,  //     Report Size (8)
+    0x95, 0x03,  //     Report Count (3)
+    0x81, 0x06,  //     Input (Data,Var,Rel,No Wrap,Linear,Preferred
+                 //     State,No Null Position)
+    0x05, 0x08,  //     Usage Page (LEDs)
+    0x19, 0x01,  //     Usage Minimum (Num Lock)
+    0x29, 0x03,  //     Usage Maximum (Scroll Lock)
+    0x15, 0x00,  //     Logical Minimum (0)
+    0x25, 0x01,  //     Logical Maximum (1)
+    0x35, 0x00,  //     Physical Minimum (0)
+    0x45, 0x01,  //     Physical Maximum (1)
+    0x75, 0x01,  //     Report Size (1)
+    0x95, 0x03,  //     Report Count (3)
+    0x91, 0x02,  //     Output (Data,Var,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position,Non-volatile)
+    0x75, 0x05,  //     Report Size (5)
+    0x95, 0x01,  //     Report Count (1)
+    0x91, 0x01,  //     Output (Const,Array,Abs,No Wrap,Linear,Preferred
+                 //     State,No Null Position,Non-volatile)
+    0xC0,        //   End Collection
+    0xC0,        // End Collection
+};
+const size_t kBelkinNostromoMouseAndExtraSize =
+    base::size(kBelkinNostromoMouseAndExtra);
+
 }  // namespace device
diff --git a/services/device/hid/test_report_descriptors.h b/services/device/hid/test_report_descriptors.h
index 1985ce6..b116b64 100644
--- a/services/device/hid/test_report_descriptors.h
+++ b/services/device/hid/test_report_descriptors.h
@@ -54,6 +54,28 @@
 extern const uint8_t kMicrosoftXboxAdaptiveController[];
 extern const size_t kMicrosoftXboxAdaptiveControllerSize;
 
+// Nexus Player Controller descriptor
+extern const uint8_t kNexusPlayerController[];
+extern const size_t kNexusPlayerControllerSize;
+
+// Steam Controller descriptors
+extern const uint8_t kSteamControllerKeyboard[];
+extern const size_t kSteamControllerKeyboardSize;
+extern const uint8_t kSteamControllerMouse[];
+extern const size_t kSteamControllerMouseSize;
+extern const uint8_t kSteamControllerVendor[];
+extern const size_t kSteamControllerVendorSize;
+
+// XSkills Gamecube USB controller adapter descriptor
+extern const uint8_t kXSkillsUsbAdapter[];
+extern const size_t kXSkillsUsbAdapterSize;
+
+// Belkin Nostromo SpeedPad descriptors
+extern const uint8_t kBelkinNostromoKeyboard[];
+extern const size_t kBelkinNostromoKeyboardSize;
+extern const uint8_t kBelkinNostromoMouseAndExtra[];
+extern const size_t kBelkinNostromoMouseAndExtraSize;
+
 }  // namespace device
 
 #endif  // SERVICES_DEVICE_HID_TEST_REPORT_DESCRIPTORS_H_
diff --git a/services/device/public/cpp/hid/BUILD.gn b/services/device/public/cpp/hid/BUILD.gn
index 6ec1c2c..da35bf9 100644
--- a/services/device/public/cpp/hid/BUILD.gn
+++ b/services/device/public/cpp/hid/BUILD.gn
@@ -12,12 +12,18 @@
   sources = [
     "fake_input_service_linux.cc",
     "fake_input_service_linux.h",
+    "hid_collection.cc",
+    "hid_collection.h",
     "hid_device_filter.cc",
     "hid_device_filter.h",
+    "hid_item_state_table.cc",
+    "hid_item_state_table.h",
     "hid_report_descriptor.cc",
     "hid_report_descriptor.h",
     "hid_report_descriptor_item.cc",
     "hid_report_descriptor_item.h",
+    "hid_report_item.cc",
+    "hid_report_item.h",
     "hid_usage_and_page.cc",
     "hid_usage_and_page.h",
   ]
diff --git a/services/device/public/cpp/hid/fake_input_service_linux.h b/services/device/public/cpp/hid/fake_input_service_linux.h
index 0cfb825..391cf7cf 100644
--- a/services/device/public/cpp/hid/fake_input_service_linux.h
+++ b/services/device/public/cpp/hid/fake_input_service_linux.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 DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_
-#define DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_FAKE_INPUT_SERVICE_LINUX_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_FAKE_INPUT_SERVICE_LINUX_H_
 
 #include <map>
 #include <string>
@@ -42,4 +42,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_FAKE_INPUT_SERVICE_LINUX_H_
diff --git a/services/device/public/cpp/hid/hid_collection.cc b/services/device/public/cpp/hid/hid_collection.cc
new file mode 100644
index 0000000..473c5cf65
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_collection.cc
@@ -0,0 +1,215 @@
+// 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 "services/device/public/cpp/hid/hid_collection.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "services/device/public/cpp/hid/hid_item_state_table.h"
+
+namespace device {
+
+HidCollection::HidCollection(HidCollection* parent,
+                             uint32_t usage_page,
+                             uint32_t usage,
+                             uint32_t type)
+    : parent_(parent), usage_(usage, usage_page), collection_type_(type) {}
+
+HidCollection::~HidCollection() = default;
+
+// static
+std::vector<std::unique_ptr<HidCollection>> HidCollection::BuildCollections(
+    const std::vector<std::unique_ptr<HidReportDescriptorItem>>& items) {
+  std::vector<std::unique_ptr<HidCollection>> collections;
+  // This HID report descriptor parser implements a state machine described
+  // in the HID specification. See section 6.2.2 Report Descriptor.
+  HidItemStateTable state;
+  for (const auto& current_item : items) {
+    switch (current_item->tag()) {
+      case HidReportDescriptorItem::kTagCollection:
+        // Add a new collection. Collections at the top-most level describe
+        // separate components of the device and are often treated as separate
+        // devices. Nested components represent logical collections of fields
+        // within a report.
+        AddCollection(*current_item, collections, state);
+        state.local.Reset();
+        break;
+      case HidReportDescriptorItem::kTagEndCollection:
+        // Mark the end of the current collection. Subsequent items describe
+        // reports associated with the parent collection.
+        if (state.collection)
+          state.collection = state.collection->parent_;
+        state.local.Reset();
+        break;
+      case HidReportDescriptorItem::kTagInput:
+      case HidReportDescriptorItem::kTagOutput:
+      case HidReportDescriptorItem::kTagFeature:
+        // Add a report item to an input, output, or feature report within the
+        // current collection. The properties of the report item are determined
+        // by the current descriptor item and the current item state table.
+        // Changes to input, output, and feature reports are propagated to all
+        // ancestor collections.
+        if (state.collection) {
+          auto* collection = state.collection;
+          while (collection) {
+            collection->AddReportItem(current_item->tag(),
+                                      current_item->GetShortData(), state);
+            collection = collection->parent_;
+          }
+        }
+        state.local.Reset();
+        break;
+      case HidReportDescriptorItem::kTagPush:
+        // Push a copy of the current global state onto the stack. If there is
+        // no global state, the push has no effect and is ignored.
+        if (!state.global_stack.empty())
+          state.global_stack.push_back(state.global_stack.back());
+        break;
+      case HidReportDescriptorItem::kTagPop:
+        // Pop the top item of the global state stack, returning to the
+        // previously pushed state. If there is no such item, the pop has no
+        // effect and is ignored.
+        if (!state.global_stack.empty())
+          state.global_stack.pop_back();
+        break;
+      case HidReportDescriptorItem::kTagReportId:
+        // Update the current report ID. The report ID is global, but is not
+        // affected by push and pop. Changes to the report ID are propagated to
+        // all ancestor collections.
+        if (state.collection) {
+          state.report_id = current_item->GetShortData();
+          auto* collection = state.collection;
+          while (collection) {
+            collection->report_ids_.push_back(state.report_id);
+            collection = collection->parent_;
+          }
+        }
+        break;
+      case HidReportDescriptorItem::kTagUsagePage:
+      case HidReportDescriptorItem::kTagLogicalMinimum:
+      case HidReportDescriptorItem::kTagLogicalMaximum:
+      case HidReportDescriptorItem::kTagPhysicalMinimum:
+      case HidReportDescriptorItem::kTagPhysicalMaximum:
+      case HidReportDescriptorItem::kTagUnitExponent:
+      case HidReportDescriptorItem::kTagUnit:
+      case HidReportDescriptorItem::kTagReportSize:
+      case HidReportDescriptorItem::kTagReportCount:
+      case HidReportDescriptorItem::kTagUsage:
+      case HidReportDescriptorItem::kTagUsageMinimum:
+      case HidReportDescriptorItem::kTagUsageMaximum:
+      case HidReportDescriptorItem::kTagDesignatorIndex:
+      case HidReportDescriptorItem::kTagDesignatorMinimum:
+      case HidReportDescriptorItem::kTagDesignatorMaximum:
+      case HidReportDescriptorItem::kTagStringIndex:
+      case HidReportDescriptorItem::kTagStringMinimum:
+      case HidReportDescriptorItem::kTagStringMaximum:
+      case HidReportDescriptorItem::kTagDelimiter:
+        // Update the value associated with a local or global item in the item
+        // state table.
+        state.SetItemValue(current_item->tag(), current_item->GetShortData());
+        break;
+      default:
+        break;
+    }
+  }
+  return collections;
+}
+
+// static
+void HidCollection::AddCollection(
+    const HidReportDescriptorItem& item,
+    std::vector<std::unique_ptr<HidCollection>>& collections,
+    HidItemStateTable& state) {
+  // Extract |usage| and |usage_page| from the current state. The usage page may
+  // be set either by a global usage page, or in the high-order bytes of a local
+  // usage value. When both are provided, the local usage value takes
+  // precedence.
+  uint32_t usage = state.local.usages.empty() ? 0 : state.local.usages.front();
+  uint32_t usage_page = (usage >> 16) & 0xffff;
+  if (usage_page == 0 && !state.global_stack.empty())
+    usage_page = state.global_stack.back().usage_page;
+  // Create the new collection. If it is a child of another collection, append
+  // it to that collection's list of children. Otherwise, append it to the list
+  // of top-level collections in |collections|.
+  uint32_t collection_type = item.GetShortData();
+  auto collection = std::make_unique<HidCollection>(
+      state.collection, usage_page, usage, collection_type);
+  if (state.collection) {
+    state.collection->children_.push_back(std::move(collection));
+    state.collection = state.collection->children_.back().get();
+  } else {
+    collections.push_back(std::move(collection));
+    state.collection = collections.back().get();
+  }
+}
+
+void HidCollection::AddChildForTesting(
+    std::unique_ptr<HidCollection> collection) {
+  children_.push_back(std::move(collection));
+}
+
+void HidCollection::AddReportItem(HidReportDescriptorItem::Tag tag,
+                                  uint32_t report_info,
+                                  const HidItemStateTable& state) {
+  // Get the correct report map for the current report item (input, output,
+  // or feature). The new item will be appended to a report in this report map.
+  std::unordered_map<uint8_t, HidReport>* reports = nullptr;
+  if (tag == HidReportDescriptorItem::kTagInput)
+    reports = &input_reports_;
+  else if (tag == HidReportDescriptorItem::kTagOutput)
+    reports = &output_reports_;
+  else if (tag == HidReportDescriptorItem::kTagFeature)
+    reports = &feature_reports_;
+  else
+    return;
+  // Fetch the report with the |report_id| matching this item, or insert a new
+  // report into the map if it does not yet exist.
+  HidReport* report = nullptr;
+  auto find_it = reports->find(state.report_id);
+  if (find_it == reports->end()) {
+    auto emplace_result = reports->emplace(state.report_id, HidReport());
+    report = &emplace_result.first->second;
+  } else {
+    report = &find_it->second;
+  }
+  // Create the report item and append it to the report.
+  report->push_back(HidReportItem::Create(tag, report_info, state));
+}
+
+mojom::HidCollectionInfoPtr HidCollection::GetDetails(
+    size_t* max_input_report_bits,
+    size_t* max_output_report_bits,
+    size_t* max_feature_report_bits) {
+  DCHECK(max_input_report_bits);
+  DCHECK(max_output_report_bits);
+  DCHECK(max_feature_report_bits);
+  struct {
+    const std::unordered_map<uint8_t, HidReport>& reports;
+    size_t& max_report_bits;
+  } report_lists[]{
+      {input_reports_, *max_input_report_bits},
+      {output_reports_, *max_output_report_bits},
+      {feature_reports_, *max_feature_report_bits},
+  };
+  auto collection_info = mojom::HidCollectionInfo::New();
+  collection_info->usage =
+      mojom::HidUsageAndPage::New(usage_.usage, usage_.usage_page);
+  collection_info->report_ids.insert(collection_info->report_ids.end(),
+                                     report_ids_.begin(), report_ids_.end());
+  for (const auto& entry : report_lists) {
+    entry.max_report_bits = 0;
+    for (const auto& report : entry.reports) {
+      size_t report_bits = 0;
+      for (const auto& item : report.second)
+        report_bits += item->GetReportSize() * item->GetReportCount();
+      entry.max_report_bits = std::max(entry.max_report_bits, report_bits);
+    }
+  }
+  return collection_info;
+}
+
+}  // namespace device
diff --git a/services/device/public/cpp/hid/hid_collection.h b/services/device/public/cpp/hid/hid_collection.h
new file mode 100644
index 0000000..4f964a0
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_collection.h
@@ -0,0 +1,109 @@
+// 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 SERVICES_DEVICE_PUBLIC_CPP_HID_HID_COLLECTION_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_COLLECTION_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "services/device/public/cpp/hid/hid_report_descriptor_item.h"
+#include "services/device/public/cpp/hid/hid_report_item.h"
+#include "services/device/public/mojom/hid.mojom.h"
+
+namespace device {
+
+class HidItemStateTable;
+
+// Information about a single HID collection.
+class HidCollection {
+ public:
+  using HidReport = std::vector<std::unique_ptr<HidReportItem>>;
+
+  HidCollection(HidCollection* parent,
+                uint32_t usage_page,
+                uint32_t usage,
+                uint32_t collection_type);
+  ~HidCollection();
+
+  static std::vector<std::unique_ptr<HidCollection>> BuildCollections(
+      const std::vector<std::unique_ptr<HidReportDescriptorItem>>& items);
+
+  uint16_t GetUsagePage() const { return usage_.usage_page; }
+
+  uint16_t GetUsage() const { return usage_.usage; }
+
+  uint32_t GetCollectionType() const { return collection_type_; }
+
+  // Returns true if there are one or more report IDs associated with this
+  // collection.
+  bool HasReportId() const { return !report_ids_.empty(); }
+
+  // Returns information about the collection.
+  mojom::HidCollectionInfoPtr GetDetails(size_t* max_input_report_bits,
+                                         size_t* max_output_report_bits,
+                                         size_t* max_feature_report_bits);
+
+  const HidCollection* GetParent() const { return parent_; }
+
+  const std::vector<std::unique_ptr<HidCollection>>& GetChildren() const {
+    return children_;
+  }
+
+  const std::unordered_map<uint8_t, HidReport>& GetInputReports() const {
+    return input_reports_;
+  }
+
+  const std::unordered_map<uint8_t, HidReport>& GetOutputReports() const {
+    return output_reports_;
+  }
+
+  const std::unordered_map<uint8_t, HidReport>& GetFeatureReports() const {
+    return feature_reports_;
+  }
+
+  // Exposed for testing.
+  void AddChildForTesting(std::unique_ptr<HidCollection> child);
+  void AddReportItem(const HidReportDescriptorItem::Tag tag,
+                     uint32_t report_info,
+                     const HidItemStateTable& state);
+
+ private:
+  static void AddCollection(
+      const HidReportDescriptorItem& item,
+      std::vector<std::unique_ptr<HidCollection>>& collections,
+      HidItemStateTable& state);
+
+  // The parent collection, or nullptr if this is a top level collection.
+  HidCollection* const parent_;
+
+  // The children of this collection in the order they were encountered in the
+  // report descriptor.
+  std::vector<std::unique_ptr<HidCollection>> children_;
+
+  // The usage page and usage ID associated with this collection.
+  const mojom::HidUsageAndPage usage_;
+
+  // The type of this collection. Stored as an integer type rather than an enum
+  // to preserve reserved and vendor-defined values.
+  const uint32_t collection_type_;
+
+  // The sequence of report IDs associated with this collection in the order
+  // they were encountered in the report descriptor.
+  std::vector<uint8_t> report_ids_;
+
+  // Maps from report IDs to sequences of report items. Reports are divided by
+  // type (input, output, or feature).
+  std::unordered_map<uint8_t, HidReport> input_reports_;
+  std::unordered_map<uint8_t, HidReport> output_reports_;
+  std::unordered_map<uint8_t, HidReport> feature_reports_;
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_COLLECTION_H_
diff --git a/services/device/public/cpp/hid/hid_device_filter.h b/services/device/public/cpp/hid/hid_device_filter.h
index 431d8a47..bdb9c2e 100644
--- a/services/device/public/cpp/hid/hid_device_filter.h
+++ b/services/device/public/cpp/hid/hid_device_filter.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 DEVICE_HID_HID_DEVICE_FILTER_H_
-#define DEVICE_HID_HID_DEVICE_FILTER_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_HID_DEVICE_FILTER_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_DEVICE_FILTER_H_
 
 #include <stdint.h>
 #include <vector>
@@ -41,4 +41,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_HID_HID_DEVICE_FILTER_H_
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_DEVICE_FILTER_H_
diff --git a/services/device/public/cpp/hid/hid_item_state_table.cc b/services/device/public/cpp/hid/hid_item_state_table.cc
new file mode 100644
index 0000000..6acb2cb
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_item_state_table.cc
@@ -0,0 +1,153 @@
+// 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 "services/device/public/cpp/hid/hid_item_state_table.h"
+
+#include <limits>
+
+namespace device {
+
+namespace {
+
+bool IsGlobalItem(HidReportDescriptorItem::Tag tag) {
+  switch (tag) {
+    case HidReportDescriptorItem::kTagUsagePage:
+    case HidReportDescriptorItem::kTagLogicalMinimum:
+    case HidReportDescriptorItem::kTagLogicalMaximum:
+    case HidReportDescriptorItem::kTagPhysicalMinimum:
+    case HidReportDescriptorItem::kTagPhysicalMaximum:
+    case HidReportDescriptorItem::kTagUnitExponent:
+    case HidReportDescriptorItem::kTagUnit:
+    case HidReportDescriptorItem::kTagReportSize:
+    case HidReportDescriptorItem::kTagReportId:
+    case HidReportDescriptorItem::kTagReportCount:
+      return true;
+    default:
+      break;
+  }
+  return false;
+}
+
+uint32_t MaybeCombineUsageAndUsagePage(
+    uint32_t usage,
+    const std::vector<HidItemStateTable::HidGlobalItemState>& global_stack) {
+  // Check if the usage value already has a usage page in the upper bytes.
+  if (usage > std::numeric_limits<uint16_t>::max())
+    return usage;
+  // No global state, just return the usage value.
+  if (global_stack.empty())
+    return usage;
+  // Combine the global usage page with the usage value.
+  return (global_stack.back().usage_page << (sizeof(uint16_t) * 8)) | usage;
+}
+
+}  // namespace
+
+HidItemStateTable::HidItemStateTable() = default;
+HidItemStateTable::~HidItemStateTable() = default;
+
+void HidItemStateTable::SetItemValue(HidReportDescriptorItem::Tag tag,
+                                     uint32_t value) {
+  if (IsGlobalItem(tag)) {
+    if (global_stack.empty())
+      global_stack.emplace_back();
+    auto& global = global_stack.back();
+    switch (tag) {
+      case HidReportDescriptorItem::kTagUsagePage:
+        global.usage_page = value;
+        break;
+      case HidReportDescriptorItem::kTagLogicalMinimum:
+        global.logical_minimum = int32_t{value};
+        break;
+      case HidReportDescriptorItem::kTagLogicalMaximum:
+        global.logical_maximum = int32_t{value};
+        break;
+      case HidReportDescriptorItem::kTagPhysicalMinimum:
+        global.physical_minimum = int32_t{value};
+        break;
+      case HidReportDescriptorItem::kTagPhysicalMaximum:
+        global.physical_maximum = int32_t{value};
+        break;
+      case HidReportDescriptorItem::kTagUnitExponent:
+        global.unit_exponent = value;
+        break;
+      case HidReportDescriptorItem::kTagUnit:
+        global.unit = value;
+        break;
+      case HidReportDescriptorItem::kTagReportSize:
+        global.report_size = value;
+        break;
+      case HidReportDescriptorItem::kTagReportCount:
+        global.report_count = value;
+        break;
+      default:
+        NOTREACHED() << "Unexpected global item in HID report descriptor";
+        break;
+    }
+  } else {
+    switch (tag) {
+      case HidReportDescriptorItem::kTagUsage:
+        local.usages.push_back(
+            MaybeCombineUsageAndUsagePage(value, global_stack));
+        break;
+      case HidReportDescriptorItem::kTagUsageMinimum:
+        local.usage_minimum =
+            MaybeCombineUsageAndUsagePage(value, global_stack);
+        break;
+      case HidReportDescriptorItem::kTagUsageMaximum:
+        local.usage_maximum =
+            MaybeCombineUsageAndUsagePage(value, global_stack);
+        break;
+      case HidReportDescriptorItem::kTagDesignatorIndex:
+        local.designator_index = value;
+        break;
+      case HidReportDescriptorItem::kTagDesignatorMinimum:
+        local.designator_minimum = value;
+        break;
+      case HidReportDescriptorItem::kTagDesignatorMaximum:
+        local.designator_maximum = value;
+        break;
+      case HidReportDescriptorItem::kTagStringIndex:
+        local.string_index = value;
+        break;
+      case HidReportDescriptorItem::kTagStringMinimum:
+        local.string_minimum = value;
+        break;
+      case HidReportDescriptorItem::kTagStringMaximum:
+        local.string_maximum = value;
+        break;
+      case HidReportDescriptorItem::kTagDelimiter:
+        local.delimiter = value;
+        break;
+      default:
+        NOTREACHED() << "Unexpected local item in HID report descriptor";
+        break;
+    }
+  }
+}
+
+HidItemStateTable::HidGlobalItemState::HidGlobalItemState() = default;
+HidItemStateTable::HidGlobalItemState::HidGlobalItemState(
+    const HidGlobalItemState&) = default;
+HidItemStateTable::HidGlobalItemState::~HidGlobalItemState() = default;
+
+HidItemStateTable::HidLocalItemState::HidLocalItemState() = default;
+HidItemStateTable::HidLocalItemState::HidLocalItemState(
+    const HidLocalItemState&) = default;
+HidItemStateTable::HidLocalItemState::~HidLocalItemState() = default;
+
+void HidItemStateTable::HidLocalItemState::Reset() {
+  usages.clear();
+  usage_minimum = 0;
+  usage_maximum = 0;
+  designator_index = 0;
+  designator_minimum = 0;
+  designator_maximum = 0;
+  string_index = 0;
+  string_minimum = 0;
+  string_maximum = 0;
+  delimiter = 0;
+}
+
+}  // namespace device
diff --git a/services/device/public/cpp/hid/hid_item_state_table.h b/services/device/public/cpp/hid/hid_item_state_table.h
new file mode 100644
index 0000000..2f6ff56
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_item_state_table.h
@@ -0,0 +1,85 @@
+// 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 SERVICES_DEVICE_PUBLIC_CPP_HID_HID_ITEM_STATE_TABLE_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_ITEM_STATE_TABLE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "services/device/public/cpp/hid/hid_report_descriptor_item.h"
+#include "services/device/public/mojom/hid.mojom.h"
+
+namespace device {
+
+class HidCollection;
+
+// The item state table, used when parsing the HID report descriptor.
+class HidItemStateTable {
+ public:
+  class HidGlobalItemState {
+   public:
+    HidGlobalItemState();
+    HidGlobalItemState(const HidGlobalItemState&);
+    ~HidGlobalItemState();
+
+    // Global items. See section 6.2.2.7 of the HID specifications.
+    uint32_t usage_page = mojom::kPageUndefined;
+    int32_t logical_minimum = 0;
+    int32_t logical_maximum = 0;
+    int32_t physical_minimum = 0;
+    int32_t physical_maximum = 0;
+    uint32_t unit_exponent = 0;
+    uint32_t unit = 0;
+    uint32_t report_size = 0;
+    uint32_t report_count = 0;
+  };
+
+  class HidLocalItemState {
+   public:
+    HidLocalItemState();
+    HidLocalItemState(const HidLocalItemState&);
+    ~HidLocalItemState();
+
+    void Reset();
+
+    // Local items. See section 6.2.2.6 of the HID specifications.
+    std::vector<uint32_t> usages;
+    uint32_t usage_minimum = 0;
+    uint32_t usage_maximum = 0;
+    uint32_t designator_index = 0;
+    uint32_t designator_minimum = 0;
+    uint32_t designator_maximum = 0;
+    uint32_t string_index = 0;
+    uint32_t string_minimum = 0;
+    uint32_t string_maximum = 0;
+    uint32_t delimiter = 0;
+  };
+
+  HidItemStateTable();
+  ~HidItemStateTable();
+
+  // Set the value of a local or global item.
+  void SetItemValue(HidReportDescriptorItem::Tag tag, uint32_t value);
+
+  // The collection that will be modified when main items are encountered.
+  HidCollection* collection = nullptr;
+
+  // The report ID is part of the global item state but is not affected by push
+  // or pop items.
+  uint32_t report_id = 0;
+
+  // The global item state. The global state is represented as a stack in order
+  // to handle push and pop items. The last element holds the current state.
+  std::vector<HidGlobalItemState> global_stack;
+
+  // The local item state.
+  HidLocalItemState local;
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_ITEM_STATE_TABLE_H_
diff --git a/services/device/public/cpp/hid/hid_report_descriptor.cc b/services/device/public/cpp/hid/hid_report_descriptor.cc
index ca71cdbe..2726928 100644
--- a/services/device/public/cpp/hid/hid_report_descriptor.cc
+++ b/services/device/public/cpp/hid/hid_report_descriptor.cc
@@ -4,7 +4,10 @@
 
 #include "services/device/public/cpp/hid/hid_report_descriptor.h"
 
-#include "base/memory/ptr_util.h"
+#include <algorithm>
+#include <limits>
+#include <utility>
+
 #include "base/stl_util.h"
 
 namespace device {
@@ -19,11 +22,11 @@
   size_t header_index = 0;
   HidReportDescriptorItem* item = nullptr;
   while (header_index < bytes.size()) {
-    item = new HidReportDescriptorItem(&bytes[header_index],
-                                       bytes.size() - header_index, item);
-    items_.push_back(base::WrapUnique(item));
-    header_index += item->GetSize();
+    items_.push_back(HidReportDescriptorItem::Create(
+        &bytes[header_index], bytes.size() - header_index, item));
+    header_index += items_.back()->GetSize();
   }
+  collections_ = HidCollection::BuildCollections(items_);
 }
 
 HidReportDescriptor::~HidReportDescriptor() {}
@@ -31,126 +34,36 @@
 void HidReportDescriptor::GetDetails(
     std::vector<mojom::HidCollectionInfoPtr>* top_level_collections,
     bool* has_report_id,
-    size_t* max_input_report_size,
-    size_t* max_output_report_size,
-    size_t* max_feature_report_size) {
+    size_t* max_input_report_bytes,
+    size_t* max_output_report_bytes,
+    size_t* max_feature_report_bytes) const {
   DCHECK(top_level_collections);
-  DCHECK(max_input_report_size);
-  DCHECK(max_output_report_size);
-  DCHECK(max_feature_report_size);
+  DCHECK(has_report_id);
+  DCHECK(max_input_report_bytes);
+  DCHECK(max_output_report_bytes);
+  DCHECK(max_feature_report_bytes);
   base::STLClearObject(top_level_collections);
 
-  *has_report_id = false;
-  *max_input_report_size = 0;
-  *max_output_report_size = 0;
-  *max_feature_report_size = 0;
-
-  // Global tags data:
-  auto current_usage_page = mojom::kPageUndefined;
-  size_t current_report_count = 0;
-  size_t cached_report_count = 0;
-  size_t current_report_size = 0;
-  size_t cached_report_size = 0;
-  size_t current_input_report_size = 0;
-  size_t current_output_report_size = 0;
-  size_t current_feature_report_size = 0;
-
-  // Local tags data:
-  uint32_t current_usage = 0;
-
-  for (const auto& current_item : items()) {
-    switch (current_item->tag()) {
-      // Main tags:
-      case HidReportDescriptorItem::kTagCollection:
-        if (!current_item->parent() &&
-            (current_usage <= std::numeric_limits<uint16_t>::max())) {
-          // This is a top-level collection.
-          auto collection = mojom::HidCollectionInfo::New();
-          collection->usage = mojom::HidUsageAndPage::New(
-              static_cast<uint16_t>(current_usage),
-              static_cast<uint16_t>(current_usage_page));
-          top_level_collections->push_back(std::move(collection));
-        }
-        break;
-      case HidReportDescriptorItem::kTagInput:
-        current_input_report_size += current_report_count * current_report_size;
-        break;
-      case HidReportDescriptorItem::kTagOutput:
-        current_output_report_size +=
-            current_report_count * current_report_size;
-        break;
-      case HidReportDescriptorItem::kTagFeature:
-        current_feature_report_size +=
-            current_report_count * current_report_size;
-        break;
-
-      // Global tags:
-      case HidReportDescriptorItem::kTagUsagePage:
-        current_usage_page = current_item->GetShortData();
-        break;
-      case HidReportDescriptorItem::kTagReportId:
-        if (top_level_collections->size() > 0) {
-          // Store report ID.
-          top_level_collections->back()->report_ids.push_back(
-              current_item->GetShortData());
-          *has_report_id = true;
-
-          // Update max report sizes.
-          *max_input_report_size =
-              std::max(*max_input_report_size, current_input_report_size);
-          *max_output_report_size =
-              std::max(*max_output_report_size, current_output_report_size);
-          *max_feature_report_size =
-              std::max(*max_feature_report_size, current_feature_report_size);
-
-          // Reset the report sizes for the next report ID.
-          current_input_report_size = 0;
-          current_output_report_size = 0;
-          current_feature_report_size = 0;
-        }
-        break;
-      case HidReportDescriptorItem::kTagReportCount:
-        current_report_count = current_item->GetShortData();
-        break;
-      case HidReportDescriptorItem::kTagReportSize:
-        current_report_size = current_item->GetShortData();
-        break;
-      case HidReportDescriptorItem::kTagPush:
-        // Cache report count and size.
-        cached_report_count = current_report_count;
-        cached_report_size = current_report_size;
-        break;
-      case HidReportDescriptorItem::kTagPop:
-        // Restore cache.
-        current_report_count = cached_report_count;
-        current_report_size = cached_report_size;
-        // Reset cache.
-        cached_report_count = 0;
-        cached_report_size = 0;
-        break;
-
-      // Local tags:
-      case HidReportDescriptorItem::kTagUsage:
-        current_usage = current_item->GetShortData();
-        break;
-
-      default:
-        break;
-    }
+  size_t max_input_report_bits = 0;
+  size_t max_output_report_bits = 0;
+  size_t max_feature_report_bits = 0;
+  for (const auto& collection : collections_) {
+    size_t input_bits;
+    size_t output_bits;
+    size_t feature_bits;
+    top_level_collections->push_back(
+        collection->GetDetails(&input_bits, &output_bits, &feature_bits));
+    if (collection->HasReportId())
+      *has_report_id = true;
+    max_input_report_bits = std::max(max_input_report_bits, input_bits);
+    max_output_report_bits = std::max(max_output_report_bits, output_bits);
+    max_feature_report_bits = std::max(max_feature_report_bits, feature_bits);
   }
 
-  // Update max report sizes
-  *max_input_report_size =
-      std::max(*max_input_report_size, current_input_report_size);
-  *max_output_report_size =
-      std::max(*max_output_report_size, current_output_report_size);
-  *max_feature_report_size =
-      std::max(*max_feature_report_size, current_feature_report_size);
-
-  // Convert bits into bytes
-  *max_input_report_size /= kBitsPerByte;
-  *max_output_report_size /= kBitsPerByte;
-  *max_feature_report_size /= kBitsPerByte;
+  // Convert bits into bytes.
+  *max_input_report_bytes = max_input_report_bits / kBitsPerByte;
+  *max_output_report_bytes = max_output_report_bits / kBitsPerByte;
+  *max_feature_report_bytes = max_feature_report_bits / kBitsPerByte;
 }
 
 }  // namespace device
diff --git a/services/device/public/cpp/hid/hid_report_descriptor.h b/services/device/public/cpp/hid/hid_report_descriptor.h
index 337ea6a..650558d5 100644
--- a/services/device/public/cpp/hid/hid_report_descriptor.h
+++ b/services/device/public/cpp/hid/hid_report_descriptor.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 DEVICE_HID_HID_REPORT_DESCRIPTOR_H_
-#define DEVICE_HID_HID_REPORT_DESCRIPTOR_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -11,6 +11,7 @@
 #include <memory>
 #include <vector>
 
+#include "services/device/public/cpp/hid/hid_collection.h"
 #include "services/device/public/cpp/hid/hid_report_descriptor_item.h"
 #include "services/device/public/mojom/hid.mojom.h"
 
@@ -27,19 +28,29 @@
     return items_;
   }
 
-  // Returns top-level collections present in the descriptor,
-  // together with max report sizes
+  const std::vector<std::unique_ptr<HidCollection>>& collections() const {
+    return collections_;
+  }
+
+  // Return the top-level collections present in the descriptor,
+  // together with max report sizes.
   void GetDetails(
       std::vector<mojom::HidCollectionInfoPtr>* top_level_collections,
       bool* has_report_id,
-      size_t* max_input_report_size,
-      size_t* max_output_report_size,
-      size_t* max_feature_report_size);
+      size_t* max_input_report_bytes,
+      size_t* max_output_report_bytes,
+      size_t* max_feature_report_bytes) const;
 
  private:
+  // An ordered sequence of HidReportDescriptorItem objects representing the
+  // items that make up a HID report descriptor.
   std::vector<std::unique_ptr<HidReportDescriptorItem>> items_;
+
+  // A hierarchichal representation of the collections and reports described by
+  // the HID report descriptor.
+  std::vector<std::unique_ptr<HidCollection>> collections_;
 };
 
 }  // namespace device
 
-#endif  // DEVICE_HID_HID_REPORT_DESCRIPTOR_H_
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_H_
diff --git a/services/device/public/cpp/hid/hid_report_descriptor_item.h b/services/device/public/cpp/hid/hid_report_descriptor_item.h
index 7f7601fae..8b1a64c7e 100644
--- a/services/device/public/cpp/hid/hid_report_descriptor_item.h
+++ b/services/device/public/cpp/hid/hid_report_descriptor_item.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef DEVICE_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
-#define DEVICE_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
 
 #include <stddef.h>
 #include <stdint.h>
 
+#include <memory>
+
 namespace device {
 
 // An element of a HID report descriptor.
 class HidReportDescriptorItem {
  private:
-  friend class HidReportDescriptor;
-
   enum Type {
     kTypeMain = 0,
     kTypeGlobal = 1,
@@ -100,7 +100,11 @@
   // Can be retrieved from GetShortData()
   // when item.tag() == HidReportDescriptorItem::kTagInput
   // or HidReportDescriptorItem::kTagOutput
-  // or HidReportDescriptorItem::kTagFeature
+  // or HidReportDescriptorItem::kTagFeature.
+  // The ReportInfo struct matches the layout of the bitfield defined in section
+  // 6.2.2.5 of the Device Class Definition for HID v1.11. Pad to 32-bits so it
+  // can be safely cast to and from uint32_t.
+#pragma pack(push, 1)
   struct ReportInfo {
     uint8_t data_or_constant : 1;
     uint8_t array_or_variable : 1;
@@ -109,10 +113,14 @@
     uint8_t linear : 1;
     uint8_t preferred : 1;
     uint8_t null : 1;
-    uint8_t reserved_1 : 1;
+    uint8_t is_volatile : 1;
     uint8_t bit_field_or_buffer : 1;
-    uint8_t reserved_2 : 1;
+    uint8_t reserved : 7;
+    uint8_t reserved2[2];
   };
+#pragma pack(pop)
+  static_assert(sizeof(ReportInfo) == sizeof(uint32_t),
+                "incorrect report info size");
 
   // HID collection type.
   // Can be retrieved from GetShortData()
@@ -137,6 +145,12 @@
  public:
   ~HidReportDescriptorItem() {}
 
+  static std::unique_ptr<HidReportDescriptorItem>
+  Create(const uint8_t* bytes, size_t size, HidReportDescriptorItem* previous) {
+    return std::unique_ptr<HidReportDescriptorItem>(
+        new HidReportDescriptorItem(bytes, size, previous));
+  }
+
   // Previous element in report descriptor.
   // Owned by descriptor instance.
   HidReportDescriptorItem* previous() const { return previous_; };
@@ -158,13 +172,14 @@
   // Raw data of a short item.
   // Not valid for a long item.
   uint32_t GetShortData() const;
+  // Size of this item in bytes, including the header.
+  size_t GetSize() const;
 
   static CollectionType GetCollectionTypeFromValue(uint32_t value);
 
  private:
   size_t GetHeaderSize() const;
   size_t payload_size() const { return payload_size_; }
-  size_t GetSize() const;
 
   HidReportDescriptorItem* previous_;
   HidReportDescriptorItem* next_;
@@ -176,4 +191,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_DESCRIPTOR_ITEM_H_
diff --git a/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc b/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
index 9fa56aa..3f63b6a 100644
--- a/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
+++ b/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
@@ -5,43 +5,330 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <limits>
 #include <sstream>
+#include <unordered_map>
+#include <utility>
 
 #include "base/macros.h"
 #include "services/device/hid/test_report_descriptors.h"
 #include "services/device/public/cpp/hid/hid_report_descriptor.h"
+#include "services/device/public/cpp/hid/hid_usage_and_page.h"
 #include "services/device/public/mojom/hid.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace device {
 
+namespace {
+using HidReport = std::vector<std::unique_ptr<HidReportItem>>;
+using HidReportMap = std::unordered_map<uint8_t, HidReport>;
+using HidCollectionVector = std::vector<std::unique_ptr<HidCollection>>;
+
+// HID unit values.
+const uint32_t kUnitCandela = 0x010000e1;
+const uint32_t kUnitDegrees = 0x14;
+const uint32_t kUnitInch = 0x13;
+const uint32_t kUnitNewton = 0xe111;
+const uint32_t kUnitSecond = 0x1001;
+
+// Report info bitfield values. The bits are:
+//   bit 0: Data (0) | Constant (1)
+//   bit 1: Array (0) | Variable (1)
+//   bit 2: Absolute (0) | Relative (1)
+//   bit 3: No Wrap (0) | Wrap (1)
+//   bit 4: Linear (0) | Non-Linear (1)
+//   bit 5: Preferred State (0) | No Preferred State (1)
+//   bit 6: No Null Value (0) | Has Null Value (1)
+//   bit 7: Non-Volatile (0) | Volatile (1)
+//   bit 8: Bit Field (0) | Buffered Bytes (1)
+const uint16_t kNonNullableArray = 0x0000;
+const uint16_t kConstantArray = 0x0001;
+const uint16_t kAbsoluteVariable = 0x0002;
+const uint16_t kConstant = 0x0003;
+const uint16_t kRelativeVariable = 0x0006;
+const uint16_t kNonLinearVariable = 0x0012;
+const uint16_t kNullableArray = 0x0040;
+const uint16_t kNullableAbsoluteVariable = 0x0042;
+const uint16_t kVolatileConstant = 0x0083;
+const uint16_t kBufferedBytes = 0x0102;
+
+// Vendor usage pages.
+const uint16_t kPageVendor02 = mojom::kPageVendor + 0x02;
+const uint16_t kPageVendor05 = mojom::kPageVendor + 0x05;
+const uint16_t kPageVendor80 = mojom::kPageVendor + 0x80;
+
+// Bit-width and mask for the usage ID field in a 32-bit usage value.
+const size_t kUsageIdSizeBits = sizeof(uint16_t) * 8;
+const uint32_t kUsageIdMask = std::numeric_limits<uint16_t>::max();
+
+// Combined usage page and usage ID values. The usage page occupies the high 16
+// bits, the usage ID occupies the low 16 bits.
+const uint32_t kUsageButton = (mojom::kPageButton << kUsageIdSizeBits);
+const uint32_t kUsageConsumer = (mojom::kPageConsumer << kUsageIdSizeBits);
+const uint32_t kUsageConsumerACBack = kUsageConsumer | 0x0224;
+const uint32_t kUsageConsumerACHome = kUsageConsumer | 0x0223;
+const uint32_t kUsageConsumerControl = kUsageConsumer | 0x01;
+const uint32_t kUsageConsumerModeStep = kUsageConsumer | 0x82;
+const uint32_t kUsageDigitizer = (mojom::kPageDigitizer << kUsageIdSizeBits);
+const uint32_t kUsageDigitizerDigitizer = kUsageDigitizer | 0x01;
+const uint32_t kUsageDigitizerBarrelSwitch = kUsageDigitizer | 0x44;
+const uint32_t kUsageDigitizerInRange = kUsageDigitizer | 0x32;
+const uint32_t kUsageDigitizerPuck = kUsageDigitizer | 0x21;
+const uint32_t kUsageDigitizerStylus = kUsageDigitizer | 0x20;
+const uint32_t kUsageDigitizerTipPressure = kUsageDigitizer | 0x30;
+const uint32_t kUsageDigitizerTipSwitch = kUsageDigitizer | 0x42;
+const uint32_t kUsageGenericDesktop =
+    (mojom::kPageGenericDesktop << kUsageIdSizeBits);
+const uint32_t kUsageGenericDesktopDial =
+    kUsageGenericDesktop | mojom::kGenericDesktopDial;
+const uint32_t kUsageGenericDesktopGamePad =
+    kUsageGenericDesktop | mojom::kGenericDesktopGamePad;
+const uint32_t kUsageGenericDesktopHatSwitch =
+    kUsageGenericDesktop | mojom::kGenericDesktopHatSwitch;
+const uint32_t kUsageGenericDesktopJoystick =
+    kUsageGenericDesktop | mojom::kGenericDesktopJoystick;
+const uint32_t kUsageGenericDesktopKeyboard =
+    kUsageGenericDesktop | mojom::kGenericDesktopKeyboard;
+const uint32_t kUsageGenericDesktopMouse =
+    kUsageGenericDesktop | mojom::kGenericDesktopMouse;
+const uint32_t kUsageGenericDesktopPointer =
+    kUsageGenericDesktop | mojom::kGenericDesktopPointer;
+const uint32_t kUsageGenericDesktopRx =
+    kUsageGenericDesktop | mojom::kGenericDesktopRx;
+const uint32_t kUsageGenericDesktopRy =
+    kUsageGenericDesktop | mojom::kGenericDesktopRy;
+const uint32_t kUsageGenericDesktopRz =
+    kUsageGenericDesktop | mojom::kGenericDesktopRz;
+const uint32_t kUsageGenericDesktopSystemControl =
+    kUsageGenericDesktop | mojom::kGenericDesktopSystemControl;
+const uint32_t kUsageGenericDesktopSystemMainMenu =
+    kUsageGenericDesktop | mojom::kGenericDesktopSystemMainMenu;
+const uint32_t kUsageGenericDesktopVbrx =
+    kUsageGenericDesktop | mojom::kGenericDesktopVbrx;
+const uint32_t kUsageGenericDesktopVbry =
+    kUsageGenericDesktop | mojom::kGenericDesktopVbry;
+const uint32_t kUsageGenericDesktopVbrz =
+    kUsageGenericDesktop | mojom::kGenericDesktopVbrz;
+const uint32_t kUsageGenericDesktopVx =
+    kUsageGenericDesktop | mojom::kGenericDesktopVx;
+const uint32_t kUsageGenericDesktopVy =
+    kUsageGenericDesktop | mojom::kGenericDesktopVy;
+const uint32_t kUsageGenericDesktopVz =
+    kUsageGenericDesktop | mojom::kGenericDesktopVz;
+const uint32_t kUsageGenericDesktopWheel =
+    kUsageGenericDesktop | mojom::kGenericDesktopWheel;
+const uint32_t kUsageGenericDesktopX =
+    kUsageGenericDesktop | mojom::kGenericDesktopX;
+const uint32_t kUsageGenericDesktopY =
+    kUsageGenericDesktop | mojom::kGenericDesktopY;
+const uint32_t kUsageGenericDesktopZ =
+    kUsageGenericDesktop | mojom::kGenericDesktopZ;
+const uint32_t kUsageGenericDeviceBatteryStrength =
+    (mojom::kPageGenericDevice << kUsageIdSizeBits) | 0x20;
+const uint32_t kUsageKeyboard = (mojom::kPageKeyboard << kUsageIdSizeBits);
+const uint32_t kUsageKeyboardApplication = kUsageKeyboard | 0x65;
+const uint32_t kUsageKeyboardLeftControl = kUsageKeyboard | 0xe0;
+const uint32_t kUsageKeyboardRightGui = kUsageKeyboard | 0xe7;
+const uint32_t kUsageLedNumLock = (mojom::kPageLed << kUsageIdSizeBits) | 0x01;
+const uint32_t kUsageLedCapsLock = (mojom::kPageLed << kUsageIdSizeBits) | 0x02;
+const uint32_t kUsageLedScrollLock =
+    (mojom::kPageLed << kUsageIdSizeBits) | 0x03;
+const uint32_t kUsageLedCompose = (mojom::kPageLed << kUsageIdSizeBits) | 0x04;
+const uint32_t kUsageLedKana = (mojom::kPageLed << kUsageIdSizeBits) | 0x05;
+const uint32_t kUsageMonitorControl =
+    (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x01;
+const uint32_t kUsageMonitorEdidInfo =
+    (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x02;
+const uint32_t kUsageMonitorVdifInfo =
+    (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x03;
+const uint32_t kUsageMonitorBrightness =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x10;
+const uint32_t kUsageMonitorContrast =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x12;
+const uint32_t kUsageMonitorRedVideoGain =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x16;
+const uint32_t kUsageMonitorGreenVideoGain =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x18;
+const uint32_t kUsageMonitorBlueVideoGain =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x1a;
+const uint32_t kUsageMonitorHorizontalPosition =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x20;
+const uint32_t kUsageMonitorHorizontalSize =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x22;
+const uint32_t kUsageMonitorVerticalPosition =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x30;
+const uint32_t kUsageMonitorVerticalSize =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x32;
+const uint32_t kUsageMonitorTrapezoidalDistortion =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x42;
+const uint32_t kUsageMonitorTilt =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x44;
+const uint32_t kUsageMonitorRedVideoBlackLevel =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x6c;
+const uint32_t kUsageMonitorGreenVideoBlackLevel =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x6e;
+const uint32_t kUsageMonitorBlueVideoBlackLevel =
+    (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x70;
+const uint32_t kUsagePidSetEffectReport =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0x21;
+const uint32_t kUsagePidDuration =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0x50;
+const uint32_t kUsagePidMagnitude =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0x70;
+const uint32_t kUsagePidLoopCount =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0x7c;
+const uint32_t kUsagePidDCEnableActuators =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0x97;
+const uint32_t kUsagePidStartDelay =
+    (mojom::kPagePidPage << kUsageIdSizeBits) | 0xa7;
+const uint32_t kUsageSimulationAccelerator =
+    (mojom::kPageSimulation << kUsageIdSizeBits) | 0xc4;
+const uint32_t kUsageSimulationBrake =
+    (mojom::kPageSimulation << kUsageIdSizeBits) | 0xc5;
+const uint32_t kUsageVendor = mojom::kPageVendor << kUsageIdSizeBits;
+const uint32_t kUsageVendor02 = kPageVendor02 << kUsageIdSizeBits;
+const uint32_t kUsageVendor05 = kPageVendor05 << kUsageIdSizeBits;
+const uint32_t kUsageVendor80 = kPageVendor80 << kUsageIdSizeBits;
+
+// Report item tags.
+const HidReportDescriptorItem::Tag kInput = HidReportDescriptorItem::kTagInput;
+const HidReportDescriptorItem::Tag kOutput =
+    HidReportDescriptorItem::kTagOutput;
+const HidReportDescriptorItem::Tag kFeature =
+    HidReportDescriptorItem::kTagFeature;
+const HidReportDescriptorItem::CollectionType kCollectionTypeApplication =
+    HidReportDescriptorItem::kCollectionTypeApplication;
+const HidReportDescriptorItem::CollectionType kCollectionTypeLogical =
+    HidReportDescriptorItem::kCollectionTypeLogical;
+const HidReportDescriptorItem::CollectionType kCollectionTypePhysical =
+    kCollectionTypePhysical;
+
+}  // namespace
+
 class HidReportDescriptorTest : public testing::Test {
  protected:
   using HidUsageAndPage = mojom::HidUsageAndPage;
   using HidCollectionInfo = mojom::HidCollectionInfo;
   using HidCollectionInfoPtr = mojom::HidCollectionInfoPtr;
 
-  void SetUp() override { descriptor_ = nullptr; }
-
   void TearDown() override {
-    if (descriptor_) {
-      delete descriptor_;
-    }
+    descriptor_ = nullptr;
+    expected_collection_infos_.clear();
+    expected_collections_.clear();
+    report_id_ = 0;
+    globals_ = HidItemStateTable::HidGlobalItemState();
   }
 
  public:
+  // Add a top-level collection to |expected_collection_infos_|.
+  void AddTopCollectionInfo(HidCollectionInfoPtr collection_info) {
+    expected_collection_infos_.push_back(std::move(collection_info));
+  }
+
+  // Create a new collection and append it to |expected_collections_|.
+  HidCollection* AddTopCollection(
+      uint32_t usage,
+      HidReportDescriptorItem::CollectionType collection_type) {
+    uint16_t usage_page = (usage >> kUsageIdSizeBits) & kUsageIdMask;
+    usage = usage & kUsageIdMask;
+    expected_collections_.push_back(std::make_unique<HidCollection>(
+        nullptr, usage_page, usage, static_cast<uint32_t>(collection_type)));
+    return expected_collections_.back().get();
+  }
+
+  // Create a new collection as a child of |parent|.
+  HidCollection* AddChild(
+      HidCollection* parent,
+      uint32_t usage,
+      HidReportDescriptorItem::CollectionType collection_type) {
+    uint16_t usage_page = (usage >> kUsageIdSizeBits) & kUsageIdMask;
+    usage = usage & kUsageIdMask;
+    parent->AddChildForTesting(std::make_unique<HidCollection>(
+        parent, usage_page, usage, static_cast<uint32_t>(collection_type)));
+    return parent->GetChildren().back().get();
+  }
+
+  // Set the |report_id|. Subsequent report items will be appended to the report
+  // with this ID.
+  void SetReportId(uint8_t report_id) { report_id_ = report_id; }
+
+  // Set the |unit| and |unit_exponent|. Subsequent report items will inherit
+  // these values.
+  void SetUnitAndUnitExponent(uint32_t unit, uint32_t unit_exponent) {
+    globals_.unit = unit;
+    globals_.unit_exponent = unit_exponent;
+  }
+
+  // Set the logical and physical minimums and maximums. Subsequent report items
+  // will inherit these values.
+  void SetLogicalAndPhysicalBounds(uint32_t logical_minimum,
+                                   uint32_t logical_maximum,
+                                   uint32_t physical_minimum,
+                                   uint32_t physical_maximum) {
+    globals_.logical_minimum = int32_t{logical_minimum};
+    globals_.logical_maximum = int32_t{logical_maximum};
+    globals_.physical_minimum = int32_t{physical_minimum};
+    globals_.physical_maximum = int32_t{physical_maximum};
+  }
+
+  // Set the |report_size| in bits, and the |report_count|. Subsequent report
+  // items will inherit these values.
+  void SetReportSizeAndCount(uint32_t report_size, uint32_t report_count) {
+    globals_.report_size = report_size;
+    globals_.report_count = report_count;
+  }
+
+  // Add a report item with a size and count but no usage value.
+  void AddReportConstant(HidCollection* collection,
+                         HidReportDescriptorItem::Tag tag,
+                         uint32_t report_info) {
+    HidItemStateTable state;
+    state.global_stack.push_back(globals_);
+    state.report_id = report_id_;
+    for (const HidCollection* c = collection; c; c = c->GetParent())
+      const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
+  }
+
+  // Add a report item for one or more usages with the same size. The size of
+  // |usage_ids| is not required to be the same as the report count.
+  void AddReportItem(HidCollection* collection,
+                     HidReportDescriptorItem::Tag tag,
+                     uint32_t report_info,
+                     const std::vector<uint32_t>& usage_ids) {
+    HidItemStateTable state;
+    state.global_stack.push_back(globals_);
+    state.report_id = report_id_;
+    state.local.usages = usage_ids;
+    for (const HidCollection* c = collection; c; c = c->GetParent())
+      const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
+  }
+
+  // Add a report item for a range of usages. The item may be a variable or an
+  // array.
+  void AddReportItemRange(HidCollection* collection,
+                          HidReportDescriptorItem::Tag tag,
+                          uint32_t report_info,
+                          uint32_t usage_minimum,
+                          uint32_t usage_maximum) {
+    HidItemStateTable state;
+    state.global_stack.push_back(globals_);
+    state.report_id = report_id_;
+    state.local.usage_minimum = usage_minimum;
+    state.local.usage_maximum = usage_maximum;
+    for (const HidCollection* c = collection; c; c = c->GetParent())
+      const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
+  }
+
   void ValidateDetails(
-      const std::vector<HidCollectionInfoPtr>& expected_collection_infos,
       const bool expected_has_report_id,
       const size_t expected_max_input_report_size,
       const size_t expected_max_output_report_size,
       const size_t expected_max_feature_report_size,
       const uint8_t* bytes,
       size_t size) {
-    descriptor_ =
-        new HidReportDescriptor(std::vector<uint8_t>(bytes, bytes + size));
-
+    descriptor_ = std::make_unique<HidReportDescriptor>(
+        std::vector<uint8_t>(bytes, bytes + size));
     std::vector<HidCollectionInfoPtr> actual_collection_infos;
     bool actual_has_report_id;
     size_t actual_max_input_report_size;
@@ -52,199 +339,1261 @@
                             &actual_max_output_report_size,
                             &actual_max_feature_report_size);
 
-    ASSERT_EQ(expected_collection_infos.size(), actual_collection_infos.size());
-
+    ASSERT_EQ(expected_collection_infos_.size(),
+              actual_collection_infos.size());
     auto actual_info_iter = actual_collection_infos.begin();
-    auto expected_info_iter = expected_collection_infos.begin();
-
-    while (expected_info_iter != expected_collection_infos.end() &&
+    auto expected_info_iter = expected_collection_infos_.begin();
+    while (expected_info_iter != expected_collection_infos_.end() &&
            actual_info_iter != actual_collection_infos.end()) {
       const HidCollectionInfoPtr& expected_info = *expected_info_iter;
       const HidCollectionInfoPtr& actual_info = *actual_info_iter;
-
       ASSERT_EQ(expected_info->usage->usage_page,
                 actual_info->usage->usage_page);
       ASSERT_EQ(expected_info->usage->usage, actual_info->usage->usage);
       ASSERT_THAT(actual_info->report_ids,
                   testing::ContainerEq(expected_info->report_ids));
-
       ++expected_info_iter;
       ++actual_info_iter;
     }
-
     ASSERT_EQ(expected_has_report_id, actual_has_report_id);
     ASSERT_EQ(expected_max_input_report_size, actual_max_input_report_size);
     ASSERT_EQ(expected_max_output_report_size, actual_max_output_report_size);
     ASSERT_EQ(expected_max_feature_report_size, actual_max_feature_report_size);
   }
 
+  static void ValidateReportItem(const HidReportItem& expected,
+                                 const HidReportItem& actual) {
+    uint32_t expected_report_info =
+        *reinterpret_cast<const uint32_t*>(&expected.GetReportInfo());
+    uint32_t actual_report_info =
+        *reinterpret_cast<const uint32_t*>(&actual.GetReportInfo());
+    ASSERT_EQ(expected.GetTag(), actual.GetTag());
+    ASSERT_EQ(expected_report_info, actual_report_info);
+    ASSERT_EQ(expected.GetReportId(), actual.GetReportId());
+    ASSERT_THAT(actual.GetUsages(), testing::ContainerEq(expected.GetUsages()));
+    ASSERT_EQ(expected.GetUsageMinimum(), actual.GetUsageMinimum());
+    ASSERT_EQ(expected.GetUsageMaximum(), actual.GetUsageMaximum());
+    ASSERT_EQ(expected.GetDesignatorMinimum(), actual.GetDesignatorMinimum());
+    ASSERT_EQ(expected.GetDesignatorMaximum(), actual.GetDesignatorMaximum());
+    ASSERT_EQ(expected.GetStringMinimum(), actual.GetStringMinimum());
+    ASSERT_EQ(expected.GetStringMaximum(), actual.GetStringMaximum());
+    ASSERT_EQ(expected.GetLogicalMinimum(), actual.GetLogicalMinimum());
+    ASSERT_EQ(expected.GetLogicalMaximum(), actual.GetLogicalMaximum());
+    ASSERT_EQ(expected.GetPhysicalMinimum(), actual.GetPhysicalMinimum());
+    ASSERT_EQ(expected.GetPhysicalMaximum(), actual.GetPhysicalMaximum());
+    ASSERT_EQ(expected.GetUnitExponent(), actual.GetUnitExponent());
+    ASSERT_EQ(expected.GetUnit(), actual.GetUnit());
+    ASSERT_EQ(expected.GetReportSize(), actual.GetReportSize());
+    ASSERT_EQ(expected.GetReportCount(), actual.GetReportCount());
+  }
+
+  static void ValidateReportMap(const HidReportMap& expected_reports,
+                                const HidReportMap& actual_reports) {
+    for (const auto& expected_entry : expected_reports) {
+      auto find_it = actual_reports.find(expected_entry.first);
+      ASSERT_NE(find_it, actual_reports.end());
+      const auto& expected_report = expected_entry.second;
+      const auto& actual_report = find_it->second;
+      ASSERT_EQ(expected_report.size(), actual_report.size());
+      auto expected_item_iter = expected_report.begin();
+      auto actual_item_iter = actual_report.begin();
+      while (expected_item_iter != expected_report.end() &&
+             actual_item_iter != actual_report.end()) {
+        ValidateReportItem(**expected_item_iter, **actual_item_iter);
+        ++expected_item_iter;
+        ++actual_item_iter;
+      }
+    }
+    ASSERT_EQ(expected_reports.size(), actual_reports.size());
+  }
+
+  static void ValidateLinkCollection(const HidCollection* expected_collection,
+                                     const HidCollection* actual_collection) {
+    ASSERT_EQ(expected_collection->GetUsagePage(),
+              actual_collection->GetUsagePage());
+    ASSERT_EQ(expected_collection->GetUsage(), actual_collection->GetUsage());
+    ASSERT_EQ(expected_collection->GetCollectionType(),
+              actual_collection->GetCollectionType());
+    ValidateReportMap(expected_collection->GetInputReports(),
+                      actual_collection->GetInputReports());
+    ValidateReportMap(expected_collection->GetOutputReports(),
+                      actual_collection->GetOutputReports());
+    ValidateReportMap(expected_collection->GetFeatureReports(),
+                      actual_collection->GetFeatureReports());
+    const auto& expected_children = expected_collection->GetChildren();
+    const auto& actual_children = actual_collection->GetChildren();
+    auto expected_child_iter = expected_children.begin();
+    auto actual_child_iter = actual_children.begin();
+    while (expected_child_iter != expected_children.end() &&
+           actual_child_iter != actual_children.end()) {
+      const HidCollection* expected_child = expected_child_iter->get();
+      const HidCollection* actual_child = actual_child_iter->get();
+      ASSERT_EQ(actual_child->GetParent(), actual_collection);
+      ValidateLinkCollection(expected_child, actual_child);
+      ++expected_child_iter;
+      ++actual_child_iter;
+    }
+    ASSERT_EQ(expected_children.size(), actual_children.size());
+  }
+
+  void ValidateCollections(const uint8_t* bytes, size_t size) {
+    descriptor_ = std::make_unique<HidReportDescriptor>(
+        std::vector<uint8_t>(bytes, bytes + size));
+    const auto& actual_collections = descriptor_->collections();
+    auto actual_collection_iter = actual_collections.begin();
+    auto expected_collection_iter = expected_collections_.begin();
+    while (expected_collection_iter != expected_collections_.end() &&
+           actual_collection_iter != actual_collections.end()) {
+      ValidateLinkCollection(expected_collection_iter->get(),
+                             actual_collection_iter->get());
+      ++expected_collection_iter;
+      ++actual_collection_iter;
+    }
+    ASSERT_EQ(expected_collections_.size(), actual_collections.size());
+  }
+
  private:
-  HidReportDescriptor* descriptor_;
+  std::unique_ptr<HidReportDescriptor> descriptor_;
+  std::vector<HidCollectionInfoPtr> expected_collection_infos_;
+  HidCollectionVector expected_collections_;
+  uint8_t report_id_ = 0;
+  HidItemStateTable::HidGlobalItemState globals_;
 };
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_Digitizer) {
-  const uint16_t usage_page = mojom::kPageDigitizer;
-  const uint16_t usage = 0x01;  // Digitizer
-
   auto digitizer = HidCollectionInfo::New();
-  digitizer->usage = HidUsageAndPage::New(usage, usage_page);
+  digitizer->usage = HidUsageAndPage::New(0x01, mojom::kPageDigitizer);
+  ASSERT_EQ(IsProtected(*digitizer->usage), false);
   digitizer->report_ids = {0x01, 0x02, 0x03};
+  AddTopCollectionInfo(std::move(digitizer));
+  ValidateDetails(true, 6, 0, 0, kDigitizer, kDigitizerSize);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(digitizer));
-  ValidateDetails(expected_infos, true, 6, 0, 0, kDigitizer, kDigitizerSize);
+TEST_F(HidReportDescriptorTest, ValidateCollections_Digitizer) {
+  auto* top =
+      AddTopCollection(kUsageDigitizerDigitizer, kCollectionTypeApplication);
+  auto* puck = AddChild(top, kUsageDigitizerPuck, kCollectionTypePhysical);
+  SetReportId(0x01);
+  SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
+  SetUnitAndUnitExponent(kUnitInch, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(puck, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetUnitAndUnitExponent(0, 0);
+  SetReportSizeAndCount(1, 3);
+  AddReportItem(puck, kInput, kAbsoluteVariable,
+                {kUsageDigitizerInRange, kUsageDigitizerBarrelSwitch,
+                 kUsageDigitizerTipSwitch});
+  SetReportSizeAndCount(5, 1);
+  AddReportConstant(puck, kInput, kConstant);
+  SetReportId(0x02);
+  auto* stylus_up =
+      AddChild(top, kUsageDigitizerStylus, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
+  SetUnitAndUnitExponent(kUnitInch, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(stylus_up, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetUnitAndUnitExponent(0, 0);
+  SetReportSizeAndCount(1, 2);
+  AddReportItem(stylus_up, kInput, kAbsoluteVariable, {kUsageDigitizerInRange});
+  SetLogicalAndPhysicalBounds(0, 16, 0, 1);
+  SetReportSizeAndCount(5, 2);
+  AddReportItemRange(stylus_up, kInput, kNullableArray, kUsageButton,
+                     kUsageButton + 16);
+  SetReportSizeAndCount(2, 2);
+  AddReportConstant(stylus_up, kInput, kConstantArray);
+  SetReportId(0x03);
+  auto* stylus_down =
+      AddChild(top, kUsageDigitizerStylus, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
+  SetUnitAndUnitExponent(kUnitInch, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(stylus_down, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetUnitAndUnitExponent(0, 0);
+  SetReportSizeAndCount(1, 2);
+  AddReportItem(stylus_down, kInput, kAbsoluteVariable,
+                {kUsageDigitizerInRange, kUsageDigitizerBarrelSwitch});
+  SetReportSizeAndCount(1, 6);
+  AddReportConstant(stylus_down, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 127, 0, 45);
+  SetUnitAndUnitExponent(kUnitNewton, 4);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(stylus_down, kInput, kNonLinearVariable,
+                {kUsageDigitizerTipPressure});
+  ValidateCollections(kDigitizer, kDigitizerSize);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_Keyboard) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopKeyboard;
-
   auto keyboard = HidCollectionInfo::New();
-  keyboard->usage = HidUsageAndPage::New(usage, usage_page);
+  keyboard->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
+                                         mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*keyboard->usage), true);
+  AddTopCollectionInfo(std::move(keyboard));
+  ValidateDetails(false, 8, 1, 0, kKeyboard, kKeyboardSize);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(keyboard));
-  ValidateDetails(expected_infos, false, 8, 1, 0, kKeyboard, kKeyboardSize);
+TEST_F(HidReportDescriptorTest, ValidateCollections_Keyboard) {
+  auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
+                               kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 8);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
+                     kUsageKeyboardRightGui);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(top, kInput, kConstant);
+  SetReportSizeAndCount(1, 5);
+  AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageLedNumLock,
+                     kUsageLedKana);
+  SetReportSizeAndCount(3, 1);
+  AddReportConstant(top, kOutput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 101, 0, 0);
+  SetReportSizeAndCount(8, 6);
+  AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
+                     kUsageKeyboardApplication);
+  ValidateCollections(kKeyboard, kKeyboardSize);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_Monitor) {
-  const uint16_t usage_page = mojom::kPageMonitor0;  // USB monitor
-  const uint16_t usage = 0x01;                       // Monitor control
-
   auto monitor = HidCollectionInfo::New();
-  monitor->usage = HidUsageAndPage::New(usage, usage_page);
-  monitor->report_ids = {1, 2, 3, 4, 5};
+  monitor->usage = HidUsageAndPage::New(0x01, mojom::kPageMonitor0);
+  ASSERT_EQ(IsProtected(*monitor->usage), false);
+  monitor->report_ids = {0x01, 0x02, 0x03, 0x04, 0x05};
+  AddTopCollectionInfo(std::move(monitor));
+  ValidateDetails(true, 0, 0, 243, kMonitor, kMonitorSize);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(monitor));
-  ValidateDetails(expected_infos, true, 0, 0, 243, kMonitor, kMonitorSize);
+TEST_F(HidReportDescriptorTest, ValidateCollections_Monitor) {
+  auto* top =
+      AddTopCollection(kUsageMonitorControl, kCollectionTypeApplication);
+  SetReportId(0x01);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 128);
+  AddReportItem(top, kFeature, kBufferedBytes, {kUsageMonitorEdidInfo});
+  SetReportId(0x02);
+  SetReportSizeAndCount(8, 243);
+  AddReportItem(top, kFeature, kBufferedBytes, {kUsageMonitorVdifInfo});
+  SetReportId(0x03);
+  SetUnitAndUnitExponent(kUnitCandela, 0x0e);
+  SetReportSizeAndCount(16, 1);
+  SetLogicalAndPhysicalBounds(0, 200, 0, 0);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageMonitorBrightness});
+  SetReportId(0x04);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageMonitorContrast});
+  SetReportSizeAndCount(16, 6);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  AddReportItem(
+      top, kFeature, kAbsoluteVariable,
+      {kUsageMonitorRedVideoGain, kUsageMonitorGreenVideoGain,
+       kUsageMonitorBlueVideoGain, kUsageMonitorRedVideoBlackLevel,
+       kUsageMonitorGreenVideoBlackLevel, kUsageMonitorBlueVideoBlackLevel});
+  SetReportId(0x05);
+  SetLogicalAndPhysicalBounds(0, 127, 0, 0);
+  AddReportItem(top, kFeature, kAbsoluteVariable,
+                {kUsageMonitorHorizontalPosition, kUsageMonitorHorizontalSize,
+                 kUsageMonitorVerticalPosition, kUsageMonitorVerticalSize,
+                 kUsageMonitorTrapezoidalDistortion, kUsageMonitorTilt});
+  ValidateCollections(kMonitor, kMonitorSize);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_Mouse) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopMouse;
-
   auto mouse = HidCollectionInfo::New();
-  mouse->usage = HidUsageAndPage::New(usage, usage_page);
+  mouse->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
+                                      mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*mouse->usage), true);
+  AddTopCollectionInfo(std::move(mouse));
+  ValidateDetails(false, 3, 0, 0, kMouse, kMouseSize);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(mouse));
-  ValidateDetails(expected_infos, false, 3, 0, 0, kMouse, kMouseSize);
+TEST_F(HidReportDescriptorTest, ValidateCollections_Mouse) {
+  auto* top =
+      AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
+  auto* physical =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 3);
+  AddReportItemRange(physical, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 3);
+  SetReportSizeAndCount(5, 1);
+  AddReportConstant(physical, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(physical, kInput, kRelativeVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  ValidateCollections(kMouse, kMouseSize);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_LogitechUnifyingReceiver) {
-  const uint16_t usage_page = mojom::kPageVendor;
-  const uint16_t usage_hidpp_short = 0x01;  // Vendor-defined
-  const uint16_t usage_hidpp_long = 0x02;   // Vendor-defined
-  const uint16_t usage_hidpp_dj = 0x04;     // Vendor-defined
-
   auto hidpp_short = HidCollectionInfo::New();
-  hidpp_short->usage = HidUsageAndPage::New(usage_hidpp_short, usage_page);
+  hidpp_short->usage = HidUsageAndPage::New(0x01, mojom::kPageVendor);
+  ASSERT_EQ(IsProtected(*hidpp_short->usage), false);
   hidpp_short->report_ids = {0x10};
   auto hidpp_long = HidCollectionInfo::New();
-  hidpp_long->usage = HidUsageAndPage::New(usage_hidpp_long, usage_page);
+  hidpp_long->usage = HidUsageAndPage::New(0x02, mojom::kPageVendor);
+  ASSERT_EQ(IsProtected(*hidpp_long->usage), false);
   hidpp_long->report_ids = {0x11};
   auto hidpp_dj = HidCollectionInfo::New();
-  hidpp_dj->usage = HidUsageAndPage::New(usage_hidpp_dj, usage_page);
+  hidpp_dj->usage = HidUsageAndPage::New(0x04, mojom::kPageVendor);
+  ASSERT_EQ(IsProtected(*hidpp_dj->usage), false);
   hidpp_dj->report_ids = {0x20, 0x21};
-
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(hidpp_short));
-  expected_infos.push_back(std::move(hidpp_long));
-  expected_infos.push_back(std::move(hidpp_dj));
-  ValidateDetails(expected_infos, true, 31, 31, 0, kLogitechUnifyingReceiver,
+  AddTopCollectionInfo(std::move(hidpp_short));
+  AddTopCollectionInfo(std::move(hidpp_long));
+  AddTopCollectionInfo(std::move(hidpp_dj));
+  ValidateDetails(true, 31, 31, 0, kLogitechUnifyingReceiver,
                   kLogitechUnifyingReceiverSize);
 }
 
+TEST_F(HidReportDescriptorTest, ValidateCollections_LogitechUnifyingReceiver) {
+  auto* short_collection =
+      AddTopCollection(kUsageVendor + 0x01, kCollectionTypeApplication);
+  SetReportId(0x10);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(short_collection, kInput, kNonNullableArray,
+                {kUsageVendor + 0x01});
+  AddReportItem(short_collection, kOutput, kNonNullableArray,
+                {kUsageVendor + 0x01});
+  auto* long_collection =
+      AddTopCollection(kUsageVendor + 0x02, kCollectionTypeApplication);
+  SetReportId(0x11);
+  SetReportSizeAndCount(8, 19);
+  AddReportItem(long_collection, kInput, kNonNullableArray,
+                {kUsageVendor + 0x02});
+  AddReportItem(long_collection, kOutput, kNonNullableArray,
+                {kUsageVendor + 0x02});
+  auto* dj_collection =
+      AddTopCollection(kUsageVendor + 0x04, kCollectionTypeApplication);
+  SetReportId(0x20);
+  SetReportSizeAndCount(8, 14);
+  AddReportItem(dj_collection, kInput, kNonNullableArray,
+                {kUsageVendor + 0x41});
+  AddReportItem(dj_collection, kOutput, kNonNullableArray,
+                {kUsageVendor + 0x41});
+  SetReportId(0x21);
+  SetReportSizeAndCount(8, 31);
+  AddReportItem(dj_collection, kInput, kNonNullableArray,
+                {kUsageVendor + 0x42});
+  AddReportItem(dj_collection, kOutput, kNonNullableArray,
+                {kUsageVendor + 0x42});
+  ValidateCollections(kLogitechUnifyingReceiver, kLogitechUnifyingReceiverSize);
+}
+
 TEST_F(HidReportDescriptorTest, ValidateDetails_SonyDualshock3) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopJoystick;
-
   auto top_info = HidCollectionInfo::New();
-  top_info->usage = HidUsageAndPage::New(usage, usage_page);
+  top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
+                                         mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*top_info->usage), false);
   top_info->report_ids = {0x01, 0x02, 0xee, 0xef};
+  AddTopCollectionInfo(std::move(top_info));
+  ValidateDetails(true, 48, 48, 48, kSonyDualshock3, kSonyDualshock3Size);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(top_info));
-  ValidateDetails(expected_infos, true, 48, 48, 48, kSonyDualshock3,
-                  kSonyDualshock3Size);
+TEST_F(HidReportDescriptorTest, ValidateCollections_SonyDualshock3) {
+  auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
+                               kCollectionTypeApplication);
+  auto* joystick = AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
+  SetReportId(0x01);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(joystick, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetReportSizeAndCount(1, 19);
+  AddReportItemRange(joystick, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 19);
+  SetReportSizeAndCount(1, 13);
+  AddReportConstant(joystick, kInput, kConstant);
+  auto* stick_axes =
+      AddChild(joystick, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 255);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(stick_axes, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopZ, kUsageGenericDesktopRz});
+  SetReportSizeAndCount(8, 39);
+  AddReportItem(joystick, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  SetReportSizeAndCount(8, 48);
+  AddReportItem(joystick, kOutput, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  AddReportItem(joystick, kFeature, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  auto* report_02_collection =
+      AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
+  SetReportId(0x02);
+  AddReportItem(report_02_collection, kFeature, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  auto* report_ee_collection =
+      AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
+  SetReportId(0xee);
+  AddReportItem(report_ee_collection, kFeature, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  auto* report_ef_collection =
+      AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
+  SetReportId(0xef);
+  AddReportItem(report_ef_collection, kFeature, kAbsoluteVariable,
+                {kUsageGenericDesktopPointer});
+  ValidateCollections(kSonyDualshock3, kSonyDualshock3Size);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_SonyDualshock4) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopGamePad;
-
   auto top_info = HidCollectionInfo::New();
-  top_info->usage = HidUsageAndPage::New(usage, usage_page);
+  top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
+                                         mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*top_info->usage), false);
   top_info->report_ids = {0x01, 0x05, 0x04, 0x02, 0x08, 0x10, 0x11, 0x12, 0x13,
                           0x14, 0x15, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
                           0x87, 0x88, 0x89, 0x90, 0x91, 0x92, 0x93, 0xa0, 0xa1,
                           0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xf0, 0xf1, 0xf2, 0xa7,
                           0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0};
+  AddTopCollectionInfo(std::move(top_info));
+  ValidateDetails(true, 63, 31, 63, kSonyDualshock4, kSonyDualshock4Size);
+}
 
-  std::vector<HidCollectionInfoPtr> expected_infos;
-  expected_infos.push_back(std::move(top_info));
-  ValidateDetails(expected_infos, true, 63, 31, 63, kSonyDualshock4,
-                  kSonyDualshock4Size);
+TEST_F(HidReportDescriptorTest, ValidateCollections_SonyDualshock4) {
+  auto* top =
+      AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
+  SetReportId(0x01);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopZ, kUsageGenericDesktopRz});
+  SetLogicalAndPhysicalBounds(0, 7, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(top, kInput, kNullableAbsoluteVariable,
+                {kUsageGenericDesktopHatSwitch});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 315);
+  SetUnitAndUnitExponent(0, 0);
+  SetReportSizeAndCount(1, 14);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 14);
+  SetLogicalAndPhysicalBounds(0, 127, 0, 315);
+  SetReportSizeAndCount(6, 1);
+  AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x20});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 315);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
+  SetReportSizeAndCount(8, 54);
+  AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x21});
+  SetReportId(0x05);
+  SetReportSizeAndCount(8, 31);
+  AddReportItem(top, kOutput, kAbsoluteVariable, {kUsageVendor + 0x22});
+  SetReportId(0x04);
+  SetReportSizeAndCount(8, 36);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x23});
+  SetReportId(0x02);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x24});
+  SetReportId(0x08);
+  SetReportSizeAndCount(8, 3);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x25});
+  SetReportId(0x10);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x26});
+  SetReportId(0x11);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x27});
+  SetReportId(0x12);
+  SetReportSizeAndCount(8, 15);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor02 + 0x21});
+  SetReportId(0x13);
+  SetReportSizeAndCount(8, 22);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor02 + 0x22});
+  SetReportId(0x14);
+  SetReportSizeAndCount(8, 16);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor05 + 0x20});
+  SetReportId(0x15);
+  SetReportSizeAndCount(8, 44);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor05 + 0x21});
+  SetReportId(0x80);
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x20});
+  SetReportId(0x81);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x21});
+  SetReportId(0x82);
+  SetReportSizeAndCount(8, 5);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x22});
+  SetReportId(0x83);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x23});
+  SetReportId(0x84);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x24});
+  SetReportId(0x85);
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x25});
+  SetReportId(0x86);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x26});
+  SetReportId(0x87);
+  SetReportSizeAndCount(8, 35);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x27});
+  SetReportId(0x88);
+  SetReportSizeAndCount(8, 34);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x28});
+  SetReportId(0x89);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x29});
+  SetReportId(0x90);
+  SetReportSizeAndCount(8, 5);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x30});
+  SetReportId(0x91);
+  SetReportSizeAndCount(8, 3);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x31});
+  SetReportId(0x92);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x32});
+  SetReportId(0x93);
+  SetReportSizeAndCount(8, 12);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x33});
+  SetReportId(0xa0);
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x40});
+  SetReportId(0xa1);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x41});
+  SetReportId(0xa2);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x42});
+  SetReportId(0xa3);
+  SetReportSizeAndCount(8, 48);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x43});
+  SetReportId(0xa4);
+  SetReportSizeAndCount(8, 13);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x44});
+  SetReportId(0xa5);
+  SetReportSizeAndCount(8, 21);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x45});
+  SetReportId(0xa6);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x46});
+  SetReportId(0xf0);
+  SetReportSizeAndCount(8, 63);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x47});
+  SetReportId(0xf1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x48});
+  SetReportId(0xf2);
+  SetReportSizeAndCount(8, 15);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x49});
+  SetReportId(0xa7);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4a});
+  SetReportId(0xa8);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4b});
+  SetReportId(0xa9);
+  SetReportSizeAndCount(8, 8);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4c});
+  SetReportId(0xaa);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4e});
+  SetReportId(0xab);
+  SetReportSizeAndCount(8, 57);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4f});
+  SetReportId(0xac);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x50});
+  SetReportId(0xad);
+  SetReportSizeAndCount(8, 11);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x51});
+  SetReportId(0xae);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x52});
+  SetReportId(0xaf);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x53});
+  SetReportId(0xb0);
+  SetReportSizeAndCount(8, 63);
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x54});
+  ValidateCollections(kSonyDualshock4, kSonyDualshock4Size);
 }
 
 TEST_F(HidReportDescriptorTest, ValidateDetails_XboxWirelessController) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopGamePad;
-
   auto top_info = HidCollectionInfo::New();
-  top_info->usage = HidUsageAndPage::New(usage, usage_page);
+  top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
+                                         mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*top_info->usage), false);
   top_info->report_ids = {0x01, 0x02, 0x03, 0x04};
-
-  std::vector<HidCollectionInfoPtr> expected_info;
-  expected_info.push_back(std::move(top_info));
-  ValidateDetails(expected_info, true, 15, 8, 0,
-                  kMicrosoftXboxWirelessController,
+  AddTopCollectionInfo(std::move(top_info));
+  ValidateDetails(true, 15, 8, 0, kMicrosoftXboxWirelessController,
                   kMicrosoftXboxWirelessControllerSize);
 }
 
+TEST_F(HidReportDescriptorTest, ValidateCollections_XboxWirelessController) {
+  auto* top =
+      AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
+  SetReportId(0x01);
+  auto* left_stick =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(left_stick, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  auto* right_stick =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  AddReportItem(right_stick, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(top, kInput, kAbsoluteVariable, {kUsageGenericDesktopZ});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(top, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(top, kInput, kAbsoluteVariable, {kUsageGenericDesktopRz});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(top, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(1, 8, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(top, kInput, kNullableAbsoluteVariable,
+                {kUsageGenericDesktopHatSwitch});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetUnitAndUnitExponent(0, 0);
+  AddReportConstant(top, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 10);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 10);
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(top, kInput, kConstant);
+  SetReportId(0x02);
+  auto* mode_collection =
+      AddChild(top, kUsageGenericDesktopSystemControl, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 1);
+  AddReportItem(mode_collection, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopSystemMainMenu});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(7, 1);
+  AddReportConstant(mode_collection, kInput, kConstant);
+  SetReportId(0x03);
+  auto* pid_collection =
+      AddChild(top, kUsagePidSetEffectReport, kCollectionTypeLogical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidDCEnableActuators});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  AddReportConstant(pid_collection, kOutput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidMagnitude});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetUnitAndUnitExponent(kUnitSecond, 0x0e);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidDuration});
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidStartDelay});
+  SetUnitAndUnitExponent(0, 0);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidLoopCount});
+  SetReportId(0x04);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDeviceBatteryStrength});
+  ValidateCollections(kMicrosoftXboxWirelessController,
+                      kMicrosoftXboxWirelessControllerSize);
+}
+
 TEST_F(HidReportDescriptorTest, ValidateDetails_NintendoSwitchProController) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage = mojom::kGenericDesktopJoystick;
-
   auto top_info = HidCollectionInfo::New();
-  top_info->usage = HidUsageAndPage::New(usage, usage_page);
+  top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
+                                         mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*top_info->usage), false);
   top_info->report_ids = {0x30, 0x21, 0x81, 0x01, 0x10, 0x80, 0x82};
-
-  std::vector<HidCollectionInfoPtr> expected_info;
-  expected_info.push_back(std::move(top_info));
-  ValidateDetails(expected_info, true, 63, 63, 0, kNintendoSwitchProController,
+  AddTopCollectionInfo(std::move(top_info));
+  ValidateDetails(true, 63, 63, 0, kNintendoSwitchProController,
                   kNintendoSwitchProControllerSize);
 }
 
+TEST_F(HidReportDescriptorTest,
+       ValidateCollections_NintendoSwitchProController) {
+  auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
+                               kCollectionTypeApplication);
+  SetReportId(0x30);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetUnitAndUnitExponent(0, 0);
+  SetReportSizeAndCount(1, 10);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 10);
+  SetReportSizeAndCount(1, 4);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 11,
+                     kUsageButton + 14);
+  SetReportSizeAndCount(1, 2);
+  AddReportConstant(top, kInput, kConstant);
+  auto* stick_axes =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  SetReportSizeAndCount(16, 4);
+  AddReportItem(stick_axes, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopZ, kUsageGenericDesktopRz});
+  SetLogicalAndPhysicalBounds(0, 7, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopHatSwitch});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 315);
+  SetReportSizeAndCount(1, 4);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 15,
+                     kUsageButton + 18);
+  SetReportSizeAndCount(8, 52);
+  AddReportConstant(top, kInput, kConstant);
+  SetReportId(0x21);
+  SetReportSizeAndCount(8, 63);
+  AddReportItem(top, kInput, kConstant, {kUsageVendor + 0x01});
+  SetReportId(0x81);
+  AddReportItem(top, kInput, kConstant, {kUsageVendor + 0x02});
+  SetReportId(0x01);
+  AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x03});
+  SetReportId(0x10);
+  AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x04});
+  SetReportId(0x80);
+  AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x05});
+  SetReportId(0x82);
+  AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x06});
+  ValidateCollections(kNintendoSwitchProController,
+                      kNintendoSwitchProControllerSize);
+}
+
 TEST_F(HidReportDescriptorTest, ValidateDetails_XboxAdaptiveController) {
-  const uint16_t usage_page = mojom::kPageGenericDesktop;
-  const uint16_t usage_gamepad = mojom::kGenericDesktopGamePad;
-  const uint16_t usage_keyboard = mojom::kGenericDesktopKeyboard;
-  const uint8_t report_ids_gamepad[] = {0x01, 0x02, 0x03, 0x04, 0x06,
-                                        0x07, 0x08, 0x09, 0x0a, 0x0b};
-  const size_t report_ids_gamepad_size = base::size(report_ids_gamepad);
-  const uint8_t report_ids_keyboard[] = {0x05};
-  const size_t report_ids_keyboard_size = base::size(report_ids_keyboard);
-
   auto gamepad_info = HidCollectionInfo::New();
-  gamepad_info->usage = HidUsageAndPage::New(usage_gamepad, usage_page);
-  gamepad_info->report_ids.insert(gamepad_info->report_ids.begin(),
-                                  report_ids_gamepad,
-                                  report_ids_gamepad + report_ids_gamepad_size);
-
+  gamepad_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
+                                             mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*gamepad_info->usage), false);
+  gamepad_info->report_ids = {0x01, 0x02, 0x03, 0x04, 0x06,
+                              0x07, 0x08, 0x09, 0x0a, 0x0b};
   auto keyboard_info = HidCollectionInfo::New();
-  keyboard_info->usage = HidUsageAndPage::New(usage_keyboard, usage_page);
-  keyboard_info->report_ids.insert(
-      keyboard_info->report_ids.begin(), report_ids_keyboard,
-      report_ids_keyboard + report_ids_keyboard_size);
-
-  std::vector<HidCollectionInfoPtr> expected_info;
-  expected_info.push_back(std::move(gamepad_info));
-  expected_info.push_back(std::move(keyboard_info));
-  ValidateDetails(expected_info, true, 54, 8, 64,
-                  kMicrosoftXboxAdaptiveController,
+  keyboard_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
+                                              mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*keyboard_info->usage), true);
+  keyboard_info->report_ids = {0x05};
+  AddTopCollectionInfo(std::move(gamepad_info));
+  AddTopCollectionInfo(std::move(keyboard_info));
+  ValidateDetails(true, 54, 8, 64, kMicrosoftXboxAdaptiveController,
                   kMicrosoftXboxAdaptiveControllerSize);
 }
 
+TEST_F(HidReportDescriptorTest, ValidateCollections_XboxAdaptiveController) {
+  auto* gamepad =
+      AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
+  SetReportId(0x01);
+  auto* left_stick =
+      AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(left_stick, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY});
+  auto* right_stick =
+      AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  AddReportItem(right_stick, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopZ, kUsageGenericDesktopRz});
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageSimulationBrake});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable,
+                {kUsageSimulationAccelerator});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(1, 8, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
+                {kUsageGenericDesktopHatSwitch});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetUnitAndUnitExponent(0, 0);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 15);
+  AddReportItemRange(gamepad, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 15);
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(1, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageConsumerACBack});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(7, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  auto* left_stick2 =
+      AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  SetReportSizeAndCount(16, 2);
+  AddReportItem(left_stick2, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopVx, kUsageGenericDesktopVy});
+  auto* right_stick2 =
+      AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
+  AddReportItem(right_stick2, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopVbrx, kUsageGenericDesktopVbry});
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageGenericDesktopVz});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
+  SetReportSizeAndCount(10, 1);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageGenericDesktopVbrz});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(6, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(1, 8, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
+                {kUsageGenericDesktopDial});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetUnitAndUnitExponent(0, 0);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 15);
+  AddReportItemRange(gamepad, kInput, kAbsoluteVariable, kUsageButton + 16,
+                     kUsageButton + 30);
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(1, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageConsumerModeStep});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(7, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  auto* consumer_collection =
+      AddChild(gamepad, kUsageConsumerControl, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0x81});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  AddReportConstant(consumer_collection, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0x84});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  AddReportConstant(consumer_collection, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0x85});
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0x99});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  AddReportConstant(consumer_collection, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0x9e});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xa1});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xa2});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xa3});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xa4});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xb9});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xba});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xbb});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xbe});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc0});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc1});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc2});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc3});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc4});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc5});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc6});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc7});
+  AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumer + 0xc8});
+  SetReportId(0x02);
+  auto* mode_collection =
+      AddChild(gamepad, kUsageConsumerControl, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 1);
+  AddReportItem(mode_collection, kInput, kAbsoluteVariable,
+                {kUsageConsumerACHome});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  SetReportSizeAndCount(7, 1);
+  AddReportConstant(mode_collection, kInput, kConstant);
+  SetReportId(0x03);
+  auto* pid_collection =
+      AddChild(gamepad, kUsagePidSetEffectReport, kCollectionTypeLogical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidDCEnableActuators});
+  SetLogicalAndPhysicalBounds(0, 0, 0, 0);
+  AddReportConstant(pid_collection, kOutput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidMagnitude});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetUnitAndUnitExponent(kUnitSecond, 0x0e);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidDuration});
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidStartDelay});
+  SetUnitAndUnitExponent(0, 0);
+  AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
+                {kUsagePidLoopCount});
+  SetReportId(0x04);
+  AddReportItem(gamepad, kInput, kAbsoluteVariable,
+                {kUsageGenericDeviceBatteryStrength});
+  SetReportId(0x06);
+  auto* report_06_collection =
+      AddChild(gamepad, kUsageVendor + 0x01, kCollectionTypeLogical);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x01});
+  AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x02});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x03});
+  SetReportSizeAndCount(8, 60);
+  AddReportItem(report_06_collection, kFeature, kBufferedBytes,
+                {kUsageVendor + 0x04});
+  SetReportId(0x07);
+  auto* report_07_collection =
+      AddChild(gamepad, kUsageVendor + 0x02, kCollectionTypeLogical);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x05});
+  AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x06});
+  AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x07});
+  SetReportId(0x08);
+  auto* report_08_collection =
+      AddChild(gamepad, kUsageVendor + 0x03, kCollectionTypeLogical);
+  AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x08});
+  AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x09});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x0a});
+  SetReportId(0x09);
+  auto* report_09_collection =
+      AddChild(gamepad, kUsageVendor + 0x04, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+  AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x0b});
+  AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x0c});
+  AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x0d});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x0e});
+  SetReportSizeAndCount(8, 60);
+  AddReportItem(report_09_collection, kFeature, kBufferedBytes,
+                {kUsageVendor + 0x0f});
+  SetReportId(0x0a);
+  auto* report_0a_collection =
+      AddChild(gamepad, kUsageVendor + 0x05, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 0x7fffffff, 0, 0);
+  SetReportSizeAndCount(32, 1);
+  AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
+                {kUsageVendor + 0x10});
+  AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
+                {kUsageVendor + 0x11});
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 2);
+  AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
+                {kUsageVendor + 0x12});
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
+                {kUsageVendor + 0x13});
+  SetReportId(0x0b);
+  auto* report_0b_collection =
+      AddChild(gamepad, kUsageVendor + 0x06, kCollectionTypeLogical);
+  SetLogicalAndPhysicalBounds(0, 100, 0, 0);
+
+  AddReportItem(report_0b_collection, kFeature, kAbsoluteVariable,
+                {kUsageVendor + 0x14});
+  SetReportId(0x05);
+  auto* keyboard = AddTopCollection(kUsageGenericDesktopKeyboard,
+                                    kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 8);
+  AddReportItemRange(keyboard, kInput, kAbsoluteVariable,
+                     kUsageKeyboardLeftControl, kUsageKeyboardRightGui);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(keyboard, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 101, 0, 0);
+  SetReportSizeAndCount(8, 6);
+  AddReportItemRange(keyboard, kInput, kNonNullableArray, kUsageKeyboard,
+                     kUsageKeyboardApplication);
+  ValidateCollections(kMicrosoftXboxAdaptiveController,
+                      kMicrosoftXboxAdaptiveControllerSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_NexusPlayerController) {
+  auto gamepad_info = HidCollectionInfo::New();
+  gamepad_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
+                                             mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*gamepad_info->usage), false);
+  gamepad_info->report_ids = {0x01, 0x02};
+  auto status_info = HidCollectionInfo::New();
+  status_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
+                                            mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*status_info->usage), false);
+  status_info->report_ids = {0x03};
+  AddTopCollectionInfo(std::move(gamepad_info));
+  AddTopCollectionInfo(std::move(status_info));
+  ValidateDetails(true, 8, 1, 0, kNexusPlayerController,
+                  kNexusPlayerControllerSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_NexusPlayerController) {
+  auto* gamepad =
+      AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
+  SetReportId(0x01);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 11);
+  AddReportItem(
+      gamepad, kInput, kAbsoluteVariable,
+      {kUsageButton + 1, kUsageButton + 2, kUsageButton + 4, kUsageButton + 5,
+       kUsageButton + 7, kUsageButton + 8, kUsageButton + 14, kUsageButton + 15,
+       kUsageButton + 13, kUsageConsumerACBack, kUsageConsumerACHome});
+  SetReportSizeAndCount(1, 1);
+  AddReportConstant(gamepad, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 7, 0, 315);
+  SetUnitAndUnitExponent(kUnitDegrees, 0);
+  SetReportSizeAndCount(4, 1);
+  AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
+                {kUsageGenericDesktopHatSwitch});
+  SetUnitAndUnitExponent(0, 0);
+  auto* axes_collection =
+      AddChild(gamepad, kUsageGenericDesktop, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 255);
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(axes_collection, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopZ, kUsageGenericDesktopRz,
+                 kUsageSimulationBrake, kUsageSimulationAccelerator});
+  SetReportId(0x02);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 255);
+  SetReportSizeAndCount(1, 4);
+  AddReportItem(gamepad, kOutput, kAbsoluteVariable,
+                {kUsageLedNumLock, kUsageLedCapsLock, kUsageLedScrollLock,
+                 kUsageLedCompose});
+  SetReportSizeAndCount(4, 1);
+  AddReportConstant(gamepad, kOutput, kConstant);
+  SetReportId(0x03);
+  auto* status =
+      AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 255);
+  SetReportSizeAndCount(8, 1);
+  AddReportItem(status, kInput, kAbsoluteVariable,
+                {kUsageGenericDeviceBatteryStrength});
+  SetReportSizeAndCount(8, 6);
+  AddReportItem(status, kInput, kAbsoluteVariable, {0xffbcbdad});
+  ValidateCollections(kNexusPlayerController, kNexusPlayerControllerSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerKeyboard) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
+                                     mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*info->usage), true);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 8, 1, 0, kSteamControllerKeyboard,
+                  kSteamControllerKeyboardSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerKeyboard) {
+  auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
+                               kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 8);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
+                     kUsageKeyboardRightGui);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(top, kInput, kConstantArray);
+  SetReportSizeAndCount(1, 5);
+  AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageLedNumLock,
+                     kUsageLedKana);
+  SetReportSizeAndCount(3, 1);
+  AddReportConstant(top, kOutput, kConstantArray);
+  SetReportSizeAndCount(8, 6);
+  SetLogicalAndPhysicalBounds(0, 101, 0, 0);
+  AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
+                     kUsageKeyboardApplication);
+  ValidateCollections(kSteamControllerKeyboard, kSteamControllerKeyboardSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerMouse) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
+                                     mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*info->usage), true);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 4, 0, 0, kSteamControllerMouse,
+                  kSteamControllerMouseSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerMouse) {
+  auto* top =
+      AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
+  auto* pointer =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 5);
+  AddReportItemRange(pointer, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 5);
+  SetReportSizeAndCount(3, 1);
+  AddReportConstant(pointer, kInput, kConstantArray);
+  SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
+  SetReportSizeAndCount(8, 3);
+  AddReportItem(pointer, kInput, kRelativeVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopWheel});
+  ValidateCollections(kSteamControllerMouse, kSteamControllerMouseSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerVendor) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(0x01, mojom::kPageVendor);
+  ASSERT_EQ(IsProtected(*info->usage), false);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 64, 64, 64, kSteamControllerVendor,
+                  kSteamControllerVendorSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerVendor) {
+  auto* top = AddTopCollection(kUsageVendor + 0x01, kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 0);
+  SetReportSizeAndCount(8, 64);
+  AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x01});
+  AddReportItem(top, kOutput, kAbsoluteVariable, {kUsageVendor + 0x01});
+  AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x01});
+  ValidateCollections(kSteamControllerVendor, kSteamControllerVendorSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_XSkillsUsbAdapter) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
+                                     mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*info->usage), false);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 7, 4, 0, kXSkillsUsbAdapter, kXSkillsUsbAdapterSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_XSkillsUsbAdapter) {
+  auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
+                               kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetReportSizeAndCount(1, 12);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 12);
+  SetReportSizeAndCount(1, 4);
+  AddReportConstant(top, kInput, kConstant);
+  SetLogicalAndPhysicalBounds(0, 255, 0, 255);
+  SetReportSizeAndCount(8, 4);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopRz, kUsageGenericDesktopZ});
+  SetLogicalAndPhysicalBounds(0, 15, 0, 15);
+  SetReportSizeAndCount(4, 2);
+  AddReportItem(top, kInput, kAbsoluteVariable,
+                {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
+  SetReportSizeAndCount(8, 4);
+  AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageVendor + 0x01,
+                     kUsageVendor + 0x04);
+  ValidateCollections(kXSkillsUsbAdapter, kXSkillsUsbAdapterSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_BelkinNostromoKeyboard) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
+                                     mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*info->usage), true);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 8, 0, 0, kBelkinNostromoKeyboard,
+                  kBelkinNostromoKeyboardSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateCollections_BelkinNostromoKeyboard) {
+  auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
+                               kCollectionTypeApplication);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 8);
+  AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
+                     kUsageKeyboardRightGui);
+  SetReportSizeAndCount(8, 1);
+  AddReportConstant(top, kInput, kConstantArray);
+  SetLogicalAndPhysicalBounds(0, 101, 0, 0);
+  SetReportSizeAndCount(8, 6);
+  AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
+                     kUsageKeyboardApplication);
+  ValidateCollections(kBelkinNostromoKeyboard, kBelkinNostromoKeyboardSize);
+}
+
+TEST_F(HidReportDescriptorTest, ValidateDetails_BelkinNostromoMouseAndExtra) {
+  auto info = HidCollectionInfo::New();
+  info->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
+                                     mojom::kPageGenericDesktop);
+  ASSERT_EQ(IsProtected(*info->usage), true);
+  AddTopCollectionInfo(std::move(info));
+  ValidateDetails(false, 4, 1, 0, kBelkinNostromoMouseAndExtra,
+                  kBelkinNostromoMouseAndExtraSize);
+}
+
+TEST_F(HidReportDescriptorTest,
+       ValidateCollections_BelkinNostromoMouseAndExtra) {
+  auto* top =
+      AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
+  auto* pointer =
+      AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
+  SetLogicalAndPhysicalBounds(0, 1, 0, 0);
+  SetReportSizeAndCount(1, 3);
+  AddReportItemRange(pointer, kInput, kAbsoluteVariable, kUsageButton + 1,
+                     kUsageButton + 3);
+  SetReportSizeAndCount(5, 1);
+  AddReportConstant(pointer, kInput, kConstantArray);
+  SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
+  SetReportSizeAndCount(8, 3);
+  AddReportItem(pointer, kInput, kRelativeVariable,
+                {kUsageGenericDesktopX, kUsageGenericDesktopY,
+                 kUsageGenericDesktopWheel});
+  SetLogicalAndPhysicalBounds(0, 1, 0, 1);
+  SetReportSizeAndCount(1, 3);
+  AddReportItemRange(pointer, kOutput, kAbsoluteVariable, kUsageLedNumLock,
+                     kUsageLedScrollLock);
+  SetReportSizeAndCount(5, 1);
+  AddReportConstant(pointer, kOutput, kConstantArray);
+  ValidateCollections(kBelkinNostromoMouseAndExtra,
+                      kBelkinNostromoMouseAndExtraSize);
+}
+
 }  // namespace device
diff --git a/services/device/public/cpp/hid/hid_report_item.cc b/services/device/public/cpp/hid/hid_report_item.cc
new file mode 100644
index 0000000..eeab22a
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_report_item.cc
@@ -0,0 +1,41 @@
+// 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 "services/device/public/cpp/hid/hid_report_item.h"
+
+#include "services/device/public/mojom/hid.mojom.h"
+
+namespace device {
+
+HidReportItem::HidReportItem(HidReportDescriptorItem::Tag tag,
+                             uint32_t short_data,
+                             const HidItemStateTable& state)
+    : tag_(tag),
+      report_info_(
+          *reinterpret_cast<HidReportDescriptorItem::ReportInfo*>(&short_data)),
+      report_id_(state.report_id),
+      local_(state.local),
+      global_(state.global_stack.empty()
+                  ? HidItemStateTable::HidGlobalItemState()
+                  : state.global_stack.back()),
+      is_range_(state.local.usage_minimum != state.local.usage_maximum),
+      has_strings_(state.local.string_index ||
+                   (state.local.string_minimum != state.local.string_maximum)),
+      has_designators_(
+          state.local.designator_index ||
+          (state.local.designator_minimum != state.local.designator_maximum)) {
+  global_.usage_page = mojom::kPageUndefined;
+  if (state.local.string_index) {
+    local_.string_minimum = state.local.string_index;
+    local_.string_maximum = state.local.string_index;
+  }
+  if (state.local.designator_index) {
+    local_.designator_minimum = state.local.designator_index;
+    local_.designator_maximum = state.local.designator_index;
+  }
+}
+
+HidReportItem::~HidReportItem() = default;
+
+}  // namespace device
diff --git a/services/device/public/cpp/hid/hid_report_item.h b/services/device/public/cpp/hid/hid_report_item.h
new file mode 100644
index 0000000..eae86f8
--- /dev/null
+++ b/services/device/public/cpp/hid/hid_report_item.h
@@ -0,0 +1,135 @@
+// 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 SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_ITEM_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_ITEM_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "services/device/public/cpp/hid/hid_item_state_table.h"
+#include "services/device/public/cpp/hid/hid_report_descriptor_item.h"
+
+namespace device {
+
+class HidReportItem {
+ public:
+  HidReportItem(HidReportDescriptorItem::Tag,
+                uint32_t,
+                const HidItemStateTable&);
+  ~HidReportItem();
+
+  static std::unique_ptr<HidReportItem> Create(HidReportDescriptorItem::Tag tag,
+                                               uint32_t short_data,
+                                               const HidItemStateTable& state) {
+    return std::make_unique<HidReportItem>(tag, short_data, state);
+  }
+
+  HidReportDescriptorItem::Tag GetTag() const { return tag_; }
+
+  const HidReportDescriptorItem::ReportInfo& GetReportInfo() const {
+    return report_info_;
+  }
+
+  // Returns the report ID of the report this item is part of.
+  uint8_t GetReportId() const { return report_id_; }
+
+  // Returns true if this item defines a usage range (minimum and maximum), or
+  // false if it defines a list of usages.
+  bool IsRange() const { return is_range_; }
+
+  // Returns true if the usage or usage range has one or more strings.
+  bool HasStrings() const { return has_strings_; }
+
+  // Returns true if the usage or usage range has one or more designators.
+  bool HasDesignators() const { return has_designators_; }
+
+  // Returns true if the report item is an absolute type, or false if it is a
+  // relative type.
+  bool IsAbsolute() const { return !report_info_.absolute_or_relative; }
+
+  // Returns true if the report item is an array type. (e.g., keyboard scan
+  // codes)
+  bool IsArray() const { return !report_info_.array_or_variable; }
+
+  // If |is_range| is false, Usages returns the list of usages associated with
+  // this item.
+  const std::vector<uint32_t>& GetUsages() const { return local_.usages; }
+
+  // If |is_range| is true, UsageMinimum and UsageMaximum return the minimum and
+  // maximum for the range of usages associated with this item.
+  uint16_t GetUsageMinimum() const { return local_.usage_minimum; }
+  uint16_t GetUsageMaximum() const { return local_.usage_maximum; }
+
+  // If |has_strings| is true, StringMinimum and StringMaximum return the
+  // minimum and maximum string indices associated with this item.
+  uint16_t GetStringMinimum() const { return local_.string_minimum; }
+  uint16_t GetStringMaximum() const { return local_.string_maximum; }
+
+  // If |has_designators| is true, DesignatorMinimum and DesignatorMaximum
+  // return the minimum and maximum designator indices associated with this
+  // item.
+  uint16_t GetDesignatorMinimum() const { return local_.designator_minimum; }
+  uint16_t GetDesignatorMaximum() const { return local_.designator_maximum; }
+
+  // Returns true if the item supports reporting a value outside the logical
+  // range as a null value.
+  bool HasNull() const { return report_info_.null; }
+
+  // Returns the width of each field defined by this item, in bits.
+  uint16_t GetReportSize() const { return global_.report_size; }
+
+  // Returns the number of fields defined by this item.
+  uint16_t GetReportCount() const { return global_.report_count; }
+
+  // Returns a 32-bit value representing a unit definition for the current item,
+  // or 0 if the item is not assigned a unit.
+  uint32_t GetUnit() const { return global_.unit; }
+
+  // Returns a value representing the exponent applied to the assigned unit.
+  uint32_t GetUnitExponent() const { return global_.unit_exponent; }
+
+  // Returns signed values representing the minimum and maximum values for this
+  // item.
+  int32_t GetLogicalMinimum() const { return global_.logical_minimum; }
+  int32_t GetLogicalMaximum() const { return global_.logical_maximum; }
+
+  // Returns signed values representing the minimum and maximum values for this
+  // item in the declared units, for scaling purposes.
+  int32_t GetPhysicalMinimum() const { return global_.physical_minimum; }
+  int32_t GetPhysicalMaximum() const { return global_.physical_maximum; }
+
+ private:
+  // The tag of the main item that generated this report item. Must be
+  // kItemInput, kItemOutput, or kItemFeature.
+  HidReportDescriptorItem::Tag tag_;
+
+  // Data associated with the main item that generated this report item.
+  HidReportDescriptorItem::ReportInfo report_info_;
+
+  // The report ID associated with this report, or 0 if none.
+  uint8_t report_id_;
+
+  // A copy of the local and global item state when this report item was
+  // encountered.
+  HidItemStateTable::HidLocalItemState local_;
+  HidItemStateTable::HidGlobalItemState global_;
+
+  // If true, the usages for this item are defined by |local.usage_minimum| and
+  // |local.usage_maximum|. If false, the usages are defomed by |local.usages|.
+  bool is_range_;
+
+  // If true, one or more strings are associated with this item.
+  bool has_strings_;
+
+  // If true, one or more designators are associated with this item.
+  bool has_designators_;
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_REPORT_ITEM_H_
diff --git a/services/device/public/cpp/hid/hid_usage_and_page.h b/services/device/public/cpp/hid/hid_usage_and_page.h
index 4c82d88..b080797 100644
--- a/services/device/public/cpp/hid/hid_usage_and_page.h
+++ b/services/device/public/cpp/hid/hid_usage_and_page.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 DEVICE_HID_PUBLIC_CPP_HID_USAGE_AND_PAGE_H_
-#define DEVICE_HID_PUBLIC_CPP_HID_USAGE_AND_PAGE_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_HID_USAGE_AND_PAGE_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_USAGE_AND_PAGE_H_
 
 #include "services/device/public/mojom/hid.mojom.h"
 
@@ -14,4 +14,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_HID_PUBLIC_CPP_HID_USAGE_AND_PAGE_H_
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_USAGE_AND_PAGE_H_
diff --git a/services/device/public/mojom/hid.mojom b/services/device/public/mojom/hid.mojom
index 1de8f6f2..208a511 100644
--- a/services/device/public/mojom/hid.mojom
+++ b/services/device/public/mojom/hid.mojom
@@ -16,6 +16,7 @@
 const uint16 kPageVirtualReality = 0x03;
 const uint16 kPageSport = 0x04;
 const uint16 kPageGame = 0x05;
+const uint16 kPageGenericDevice = 0x06;
 const uint16 kPageKeyboard = 0x07;
 const uint16 kPageLed = 0x08;
 const uint16 kPageButton = 0x09;
diff --git a/services/video_capture/broadcasting_receiver.cc b/services/video_capture/broadcasting_receiver.cc
index 7f83a78..19accba6 100644
--- a/services/video_capture/broadcasting_receiver.cc
+++ b/services/video_capture/broadcasting_receiver.cc
@@ -23,6 +23,34 @@
 
 }  // anonymous namespace
 
+BroadcastingReceiver::ClientContext::ClientContext(mojom::ReceiverPtr client)
+    : client_(std::move(client)),
+      is_suspended_(false),
+      on_started_has_been_called_(false),
+      on_started_using_gpu_decode_has_been_called_(false) {}
+
+BroadcastingReceiver::ClientContext::~ClientContext() = default;
+
+BroadcastingReceiver::ClientContext::ClientContext(
+    BroadcastingReceiver::ClientContext&& other) = default;
+
+BroadcastingReceiver::ClientContext& BroadcastingReceiver::ClientContext::
+operator=(BroadcastingReceiver::ClientContext&& other) = default;
+
+void BroadcastingReceiver::ClientContext::OnStarted() {
+  if (on_started_has_been_called_)
+    return;
+  on_started_has_been_called_ = true;
+  client_->OnStarted();
+}
+
+void BroadcastingReceiver::ClientContext::OnStartedUsingGpuDecode() {
+  if (on_started_using_gpu_decode_has_been_called_)
+    return;
+  on_started_using_gpu_decode_has_been_called_ = true;
+  client_->OnStarted();
+}
+
 BroadcastingReceiver::BufferContext::BufferContext(
     int buffer_id,
     media::mojom::VideoBufferHandlePtr buffer_handle)
@@ -100,32 +128,43 @@
 int32_t BroadcastingReceiver::AddClient(mojom::ReceiverPtr client) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto client_id = next_client_id_++;
-  clients_.insert(std::make_pair(client_id, std::move(client)));
-  auto& added_client = clients_[client_id];
-  added_client.set_connection_error_handler(
+  ClientContext context(std::move(client));
+  auto& added_client_context =
+      clients_.insert(std::make_pair(client_id, std::move(context)))
+          .first->second;
+  added_client_context.client().set_connection_error_handler(
       base::BindOnce(&BroadcastingReceiver::OnClientDisconnected,
                      weak_factory_.GetWeakPtr(), client_id));
   if (status_ == Status::kOnErrorHasBeenCalled) {
-    added_client->OnError(error_);
+    added_client_context.client()->OnError(error_);
     return client_id;
   }
-  if (status_ == Status::kOnStartedHasBeenCalled)
-    added_client->OnStarted();
+  if (status_ == Status::kOnStartedHasBeenCalled) {
+    added_client_context.OnStarted();
+  }
   if (status_ == Status::kOnStartedUsingGpuDecodeHasBeenCalled)
-    added_client->OnStartedUsingGpuDecode();
+    added_client_context.OnStartedUsingGpuDecode();
 
   for (auto& buffer_context : buffer_contexts_) {
-    added_client->OnNewBuffer(buffer_context.buffer_id(),
-                              buffer_context.CloneBufferHandle());
+    added_client_context.client()->OnNewBuffer(
+        buffer_context.buffer_id(), buffer_context.CloneBufferHandle());
   }
   return client_id;
 }
 
+void BroadcastingReceiver::SuspendClient(int32_t client_id) {
+  clients_.at(client_id).set_is_suspended(true);
+}
+
+void BroadcastingReceiver::ResumeClient(int32_t client_id) {
+  clients_.at(client_id).set_is_suspended(false);
+}
+
 mojom::ReceiverPtr BroadcastingReceiver::RemoveClient(int32_t client_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto client = std::move(clients_[client_id]);
+  auto client = std::move(clients_.at(client_id));
   clients_.erase(client_id);
-  return client;
+  return std::move(client.client());
 }
 
 void BroadcastingReceiver::OnNewBuffer(
@@ -135,8 +174,8 @@
   buffer_contexts_.emplace_back(buffer_id, std::move(buffer_handle));
   auto& buffer_context = buffer_contexts_.back();
   for (auto& client : clients_) {
-    client.second->OnNewBuffer(buffer_context.buffer_id(),
-                               buffer_context.CloneBufferHandle());
+    client.second.client()->OnNewBuffer(buffer_context.buffer_id(),
+                                        buffer_context.CloneBufferHandle());
   }
 }
 
@@ -151,13 +190,15 @@
   auto& buffer_context = LookupBufferContextFromBufferId(buffer_id);
   buffer_context.set_access_permission(std::move(access_permission));
   for (auto& client : clients_) {
+    if (client.second.is_suspended())
+      continue;
     mojom::ScopedAccessPermissionPtr consumer_access_permission;
     mojo::MakeStrongBinding(
         std::make_unique<ConsumerAccessPermission>(base::BindOnce(
             &BroadcastingReceiver::OnClientFinishedConsumingFrame,
             weak_factory_.GetWeakPtr(), buffer_context.buffer_id())),
         mojo::MakeRequest(&consumer_access_permission));
-    client.second->OnFrameReadyInBuffer(
+    client.second.client()->OnFrameReadyInBuffer(
         buffer_context.buffer_id(), frame_feedback_id,
         std::move(consumer_access_permission), frame_info.Clone());
     buffer_context.IncreaseConsumerCount();
@@ -166,17 +207,23 @@
 
 void BroadcastingReceiver::OnBufferRetired(int32_t buffer_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto& buffer_context = LookupBufferContextFromBufferId(buffer_id);
+  auto context_iter =
+      std::find_if(buffer_contexts_.begin(), buffer_contexts_.end(),
+                   [buffer_id](const BufferContext& entry) {
+                     return entry.buffer_id() == buffer_id;
+                   });
+  auto& buffer_context = *context_iter;
   CHECK(!buffer_context.IsStillBeingConsumed());
+  buffer_contexts_.erase(context_iter);
   for (auto& client : clients_) {
-    client.second->OnBufferRetired(buffer_id);
+    client.second.client()->OnBufferRetired(buffer_id);
   }
 }
 
 void BroadcastingReceiver::OnError(media::VideoCaptureError error) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (auto& client : clients_) {
-    client.second->OnError(error);
+    client.second.client()->OnError(error);
   }
   status_ = Status::kOnErrorHasBeenCalled;
   error_ = error;
@@ -186,21 +233,23 @@
     media::VideoCaptureFrameDropReason reason) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (auto& client : clients_) {
-    client.second->OnFrameDropped(reason);
+    if (client.second.is_suspended())
+      continue;
+    client.second.client()->OnFrameDropped(reason);
   }
 }
 
 void BroadcastingReceiver::OnLog(const std::string& message) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (auto& client : clients_) {
-    client.second->OnLog(message);
+    client.second.client()->OnLog(message);
   }
 }
 
 void BroadcastingReceiver::OnStarted() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (auto& client : clients_) {
-    client.second->OnStarted();
+    client.second.OnStarted();
   }
   status_ = Status::kOnStartedHasBeenCalled;
 }
@@ -208,7 +257,7 @@
 void BroadcastingReceiver::OnStartedUsingGpuDecode() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (auto& client : clients_) {
-    client.second->OnStartedUsingGpuDecode();
+    client.second.OnStartedUsingGpuDecode();
   }
   status_ = Status::kOnStartedUsingGpuDecodeHasBeenCalled;
 }
diff --git a/services/video_capture/broadcasting_receiver.h b/services/video_capture/broadcasting_receiver.h
index 43f5238..19753d1 100644
--- a/services/video_capture/broadcasting_receiver.h
+++ b/services/video_capture/broadcasting_receiver.h
@@ -21,8 +21,10 @@
   BroadcastingReceiver();
   ~BroadcastingReceiver() override;
 
-  // Returns a client_id that can be used for a call to RemoveClient().
+  // Returns a client_id that can be used for a call to Suspend/Resume/Remove.
   int32_t AddClient(mojom::ReceiverPtr client);
+  void SuspendClient(int32_t client_id);
+  void ResumeClient(int32_t client_id);
   // Returns ownership of the client back to the caller.
   mojom::ReceiverPtr RemoveClient(int32_t client_id);
 
@@ -49,9 +51,28 @@
     kOnErrorHasBeenCalled,
   };
 
-  // Combines ownership of a media::mojom::VideoBufferHandlePtr with context
-  // needed for sharing the buffer as well as temporary access permission to
-  // its contents with potentially multiple consumers.
+  // Wrapper that suppresses calls to OnStarted() and OnStartedUsingGpuDecode()
+  // after they have already been called once.
+  class ClientContext {
+   public:
+    explicit ClientContext(mojom::ReceiverPtr client);
+    ~ClientContext();
+    ClientContext(ClientContext&& other);
+    ClientContext& operator=(ClientContext&& other);
+    void OnStarted();
+    void OnStartedUsingGpuDecode();
+
+    mojom::ReceiverPtr& client() { return client_; }
+    void set_is_suspended(bool suspended) { is_suspended_ = suspended; }
+    bool is_suspended() const { return is_suspended_; }
+
+   private:
+    mojom::ReceiverPtr client_;
+    bool is_suspended_;
+    bool on_started_has_been_called_;
+    bool on_started_using_gpu_decode_has_been_called_;
+  };
+
   class BufferContext {
    public:
     BufferContext(int32_t buffer_id,
@@ -83,7 +104,7 @@
   BufferContext& LookupBufferContextFromBufferId(int32_t buffer_id);
 
   SEQUENCE_CHECKER(sequence_checker_);
-  std::map<int32_t /*client_id*/, mojom::ReceiverPtr> clients_;
+  std::map<int32_t /*client_id*/, ClientContext> clients_;
   std::vector<BufferContext> buffer_contexts_;
   Status status_;
 
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.cc b/services/video_capture/device_factory_media_to_mojo_adapter.cc
index 763c214..49bcd88 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.cc
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.cc
@@ -111,7 +111,7 @@
     // Revoke the access and close the device, then bind to the new request.
     ActiveDeviceEntry& device_entry = active_device_iter->second;
     device_entry.binding->Unbind();
-    device_entry.device->Stop();
+    device_entry.device->Stop(base::DoNothing());
     device_entry.binding->Bind(std::move(device_request));
     device_entry.binding->set_connection_error_handler(base::Bind(
         &DeviceFactoryMediaToMojoAdapter::OnClientConnectionErrorOrClose,
@@ -189,7 +189,7 @@
   video_capture::uma::LogVideoCaptureServiceEvent(
       video_capture::uma::SERVICE_LOST_CONNECTION_TO_BROWSER);
 
-  active_devices_by_id_[device_id].device->Stop();
+  active_devices_by_id_[device_id].device->Stop(base::DoNothing());
   active_devices_by_id_.erase(device_id);
 }
 
diff --git a/services/video_capture/device_media_to_mojo_adapter.cc b/services/video_capture/device_media_to_mojo_adapter.cc
index f002397..c0beb8aa 100644
--- a/services/video_capture/device_media_to_mojo_adapter.cc
+++ b/services/video_capture/device_media_to_mojo_adapter.cc
@@ -29,6 +29,13 @@
       decoder_task_runner);
 }
 
+void FinishUpCallToStop(
+    std::unique_ptr<video_capture::ReceiverMojoToMediaAdapter> receiver,
+    video_capture::mojom::Device::StopCallback callback) {
+  receiver.reset();
+  std::move(callback).Run();
+}
+
 }  // anonymous namespace
 
 namespace video_capture {
@@ -144,24 +151,27 @@
   device_->TakePhoto(std::move(scoped_callback));
 }
 
-void DeviceMediaToMojoAdapter::Stop() {
+void DeviceMediaToMojoAdapter::Stop(StopCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (device_started_ == false)
+  if (!device_started_) {
+    std::move(callback).Run();
     return;
+  }
   device_started_ = false;
   weak_factory_.InvalidateWeakPtrs();
   device_->StopAndDeAllocate();
-  // We need to post the deletion of receiver to the end of the message queue,
-  // because |device_->StopAndDeAllocate()| may post messages (e.g.
-  // OnBufferRetired()) to a WeakPtr to |receiver_| to this queue, and we need
-  // those messages to be sent before we invalidate the WeakPtr.
-  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
-                                                  std::move(receiver_));
+  // We need to post a continuation of the stop routine to the end of the
+  // message queue, because |device_->StopAndDeAllocate()| may post messages
+  // (e.g. OnBufferRetired()) to a WeakPtr to |receiver_| to this queue, and we
+  // need those messages to be sent out before we continue.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(&FinishUpCallToStop, std::move(receiver_),
+                                std::move(callback)));
 }
 
 void DeviceMediaToMojoAdapter::OnClientConnectionErrorOrClose() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  Stop();
+  Stop(base::DoNothing());
 }
 
 // static
diff --git a/services/video_capture/device_media_to_mojo_adapter.h b/services/video_capture/device_media_to_mojo_adapter.h
index c238258..595de58 100644
--- a/services/video_capture/device_media_to_mojo_adapter.h
+++ b/services/video_capture/device_media_to_mojo_adapter.h
@@ -41,8 +41,8 @@
   void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override;
   void TakePhoto(TakePhotoCallback callback) override;
+  void Stop(StopCallback callback) override;
 
-  void Stop();
   void OnClientConnectionErrorOrClose();
 
   // Returns the fixed maximum number of buffers passed to the constructor
diff --git a/services/video_capture/public/cpp/mock_receiver.cc b/services/video_capture/public/cpp/mock_receiver.cc
index 54551a13..f49123f 100644
--- a/services/video_capture/public/cpp/mock_receiver.cc
+++ b/services/video_capture/public/cpp/mock_receiver.cc
@@ -4,6 +4,8 @@
 
 #include "services/video_capture/public/cpp/mock_receiver.h"
 
+#include "base/stl_util.h"
+
 namespace video_capture {
 
 MockReceiver::MockReceiver() : binding_(this) {}
@@ -16,6 +18,8 @@
 void MockReceiver::OnNewBuffer(
     int32_t buffer_id,
     media::mojom::VideoBufferHandlePtr buffer_handle) {
+  CHECK(!base::ContainsValue(known_buffer_ids_, buffer_id));
+  known_buffer_ids_.push_back(buffer_id);
   DoOnNewBuffer(buffer_id, &buffer_handle);
 }
 
@@ -28,4 +32,12 @@
                          &frame_info);
 }
 
+void MockReceiver::OnBufferRetired(int32_t buffer_id) {
+  auto iter =
+      std::find(known_buffer_ids_.begin(), known_buffer_ids_.end(), buffer_id);
+  CHECK(iter != known_buffer_ids_.end());
+  known_buffer_ids_.erase(iter);
+  DoOnBufferRetired(buffer_id);
+}
+
 }  // namespace video_capture
diff --git a/services/video_capture/public/cpp/mock_receiver.h b/services/video_capture/public/cpp/mock_receiver.h
index a5a9c306..6edfa1d 100644
--- a/services/video_capture/public/cpp/mock_receiver.h
+++ b/services/video_capture/public/cpp/mock_receiver.h
@@ -5,6 +5,8 @@
 #ifndef SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_RECEIVER_H_
 #define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_MOCK_RECEIVER_H_
 
+#include <vector>
+
 #include "media/mojo/interfaces/media_types.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/video_capture/public/mojom/receiver.mojom.h"
@@ -26,6 +28,7 @@
       int32_t frame_feedback_id,
       mojom::ScopedAccessPermissionPtr access_permission,
       media::mojom::VideoFrameInfoPtr frame_info) override;
+  void OnBufferRetired(int32_t buffer_id) override;
 
   MOCK_METHOD2(DoOnNewBuffer,
                void(int32_t, media::mojom::VideoBufferHandlePtr*));
@@ -34,7 +37,7 @@
                     int32_t frame_feedback_id,
                     mojom::ScopedAccessPermissionPtr*,
                     media::mojom::VideoFrameInfoPtr*));
-  MOCK_METHOD1(OnBufferRetired, void(int32_t));
+  MOCK_METHOD1(DoOnBufferRetired, void(int32_t));
   MOCK_METHOD1(OnError, void(media::VideoCaptureError));
   MOCK_METHOD1(OnFrameDropped, void(media::VideoCaptureFrameDropReason));
   MOCK_METHOD1(OnLog, void(const std::string&));
@@ -43,6 +46,7 @@
 
  private:
   const mojo::Binding<mojom::Receiver> binding_;
+  std::vector<int32_t> known_buffer_ids_;
 };
 
 }  // namespace video_capture
diff --git a/services/video_capture/public/mojom/device.mojom b/services/video_capture/public/mojom/device.mojom
index c4113fe..564e1f5 100644
--- a/services/video_capture/public/mojom/device.mojom
+++ b/services/video_capture/public/mojom/device.mojom
@@ -9,9 +9,12 @@
 import "services/video_capture/public/mojom/receiver.mojom";
 
 // Represents access to a video capture device available on the machine.
-// Note: Instead of offering an explicit Stop() method, the device
-// is stopped automatically when the message pipe corresponding to either the
-// Device or the given |receiver| is closed.
+// The device is stopped automatically when the message pipe corresponding to
+// either the Device or the given |receiver| is closed. Note, however, that
+// as a response to closing the device, the service may still need to send out
+// events such as Receiver.OnBufferRetired(). Clients who need to wait for this
+// to complete must explicitly call Stop() and wait for its callback to indicate
+// that all events related to stopping device have been sent out.
 interface Device {
   Start(media.mojom.VideoCaptureParams requested_settings, Receiver receiver);
   OnReceiverReportingUtilization(int32 frame_feedback_id,
@@ -25,4 +28,6 @@
       => (bool success);
   TakePhoto()
       => (media.mojom.Blob? blob);
+
+  Stop() => ();
 };
diff --git a/services/video_capture/public/mojom/video_source.mojom b/services/video_capture/public/mojom/video_source.mojom
index e84b86b..7b84e5b 100644
--- a/services/video_capture/public/mojom/video_source.mojom
+++ b/services/video_capture/public/mojom/video_source.mojom
@@ -24,7 +24,11 @@
   // pushed to |subscriber| in case the obtained settings are unacceptable.
   Activate();
 
-  // The callback event indicates that no more frames will be pushed.
+  // When suspended, the subscriber will no longer receive any calls to
+  // OnFrameReadyInBuffer() and OnFrameDropped(), but will still receive any
+  // other calls, e.g. OnNewBuffer() and OnBufferRetired().
+  // Callers may wait for the empty callback event to get notified when it is
+  // guaranteed that no more frames will be pushed.
   Suspend() => ();
 
   Resume();
diff --git a/services/video_capture/push_video_stream_subscription_impl.cc b/services/video_capture/push_video_stream_subscription_impl.cc
index 2748a6c..5455bf1 100644
--- a/services/video_capture/push_video_stream_subscription_impl.cc
+++ b/services/video_capture/push_video_stream_subscription_impl.cc
@@ -40,11 +40,12 @@
                      weak_factory_.GetWeakPtr()));
 }
 
-void PushVideoStreamSubscriptionImpl::
-    NotifySubscriberCreateSubscriptionSucceededWithSettings(
-        const media::VideoCaptureParams& settings) {
-  DCHECK_EQ(Status::kCreationCallbackNotYetRun, status_)
-      << "Illegal call in current state.";
+void PushVideoStreamSubscriptionImpl::OnDeviceStartSucceededWithSettings(
+    const media::VideoCaptureParams& settings) {
+  if (status_ != Status::kCreationCallbackNotYetRun) {
+    // Creation callback has already been run from a previous device start.
+    return;
+  }
   mojom::CreatePushSubscriptionResultCode result_code =
       settings == requested_settings_
           ? mojom::CreatePushSubscriptionResultCode::
@@ -55,10 +56,11 @@
   status_ = Status::kNotYetActivated;
 }
 
-void PushVideoStreamSubscriptionImpl::
-    NotifySubscriberCreateSubscriptionFailed() {
-  DCHECK_EQ(Status::kCreationCallbackNotYetRun, status_)
-      << "Illegal call in current state.";
+void PushVideoStreamSubscriptionImpl::OnDeviceStartFailed() {
+  if (status_ != Status::kCreationCallbackNotYetRun) {
+    // Creation callback has already been run from a previous device start.
+    return;
+  }
   std::move(creation_callback_)
       .Run(mojom::CreatePushSubscriptionResultCode::kFailed,
            requested_settings_);
@@ -76,7 +78,7 @@
   if (status_ != Status::kActive)
     return;
 
-  subscriber_ = broadcaster_->RemoveClient(broadcaster_client_id_);
+  broadcaster_->SuspendClient(broadcaster_client_id_);
   status_ = Status::kSuspended;
   std::move(callback).Run();
 }
@@ -84,7 +86,7 @@
 void PushVideoStreamSubscriptionImpl::Resume() {
   if (status_ != Status::kSuspended)
     return;
-  broadcaster_client_id_ = broadcaster_->AddClient(std::move(subscriber_));
+  broadcaster_->ResumeClient(broadcaster_client_id_);
   status_ = Status::kActive;
 }
 
@@ -139,14 +141,14 @@
     case Status::kClosed:
       std::move(callback).Run();
       return;
-    case Status::kActive:
+    case Status::kActive:  // Fall through.
+    case Status::kSuspended:
       broadcaster_->RemoveClient(broadcaster_client_id_);
       status_ = Status::kClosed;
       if (on_closed_handler_)
         std::move(on_closed_handler_).Run(std::move(callback));
       return;
-    case Status::kNotYetActivated:  // Fall through.
-    case Status::kSuspended:
+    case Status::kNotYetActivated:
       status_ = Status::kClosed;
       if (on_closed_handler_)
         std::move(on_closed_handler_).Run(std::move(callback));
diff --git a/services/video_capture/push_video_stream_subscription_impl.h b/services/video_capture/push_video_stream_subscription_impl.h
index 739fcf76..74c1dac0 100644
--- a/services/video_capture/push_video_stream_subscription_impl.h
+++ b/services/video_capture/push_video_stream_subscription_impl.h
@@ -28,9 +28,9 @@
   void SetOnClosedHandler(
       base::OnceCallback<void(base::OnceClosure done_cb)> handler);
 
-  void NotifySubscriberCreateSubscriptionSucceededWithSettings(
+  void OnDeviceStartSucceededWithSettings(
       const media::VideoCaptureParams& settings);
-  void NotifySubscriberCreateSubscriptionFailed();
+  void OnDeviceStartFailed();
 
   // mojom::PushVideoStreamSubscription implementation.
   void Activate() override;
diff --git a/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc b/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc
index 0a21043..3aa3b04 100644
--- a/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc
+++ b/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc
@@ -204,18 +204,21 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-void SharedMemoryVirtualDeviceMojoAdapter::Stop() {
+void SharedMemoryVirtualDeviceMojoAdapter::Stop(StopCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!receiver_.is_bound())
+  if (!receiver_.is_bound()) {
+    std::move(callback).Run();
     return;
+  }
   // Unsubscribe from connection error callbacks.
   receiver_.set_connection_error_handler(base::OnceClosure());
   receiver_.reset();
+  std::move(callback).Run();
 }
 
 void SharedMemoryVirtualDeviceMojoAdapter::OnReceiverConnectionErrorOrClose() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  Stop();
+  Stop(base::DoNothing());
 }
 
 }  // namespace video_capture
diff --git a/services/video_capture/shared_memory_virtual_device_mojo_adapter.h b/services/video_capture/shared_memory_virtual_device_mojo_adapter.h
index 013a31a..0a8d57e 100644
--- a/services/video_capture/shared_memory_virtual_device_mojo_adapter.h
+++ b/services/video_capture/shared_memory_virtual_device_mojo_adapter.h
@@ -46,8 +46,7 @@
   void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override;
   void TakePhoto(TakePhotoCallback callback) override;
-
-  void Stop();
+  void Stop(StopCallback callback) override;
 
   // Returns the fixed maximum number of buffers passed to the constructor
   // of VideoCaptureBufferPoolImpl.
diff --git a/services/video_capture/test/fake_device_unittest.cc b/services/video_capture/test/fake_device_unittest.cc
index 907fcca..3f9cde1 100644
--- a/services/video_capture/test/fake_device_unittest.cc
+++ b/services/video_capture/test/fake_device_unittest.cc
@@ -134,7 +134,7 @@
   wait_for_frames_loop.Run();
 
   base::RunLoop wait_for_buffers_retired_loop;
-  EXPECT_CALL(receiver, OnBufferRetired(_))
+  EXPECT_CALL(receiver, DoOnBufferRetired(_))
       .WillRepeatedly(
           Invoke([&received_buffer_ids,
                   &wait_for_buffers_retired_loop](int32_t buffer_id) {
diff --git a/services/video_capture/test/mock_device_shared_access_unittest.cc b/services/video_capture/test/mock_device_shared_access_unittest.cc
index 31a9ba9..5ef70c8f 100644
--- a/services/video_capture/test/mock_device_shared_access_unittest.cc
+++ b/services/video_capture/test/mock_device_shared_access_unittest.cc
@@ -23,6 +23,7 @@
 using testing::Invoke;
 using testing::InvokeWithoutArgs;
 using testing::Mock;
+using testing::SaveArg;
 
 namespace video_capture {
 
@@ -37,20 +38,21 @@
 
   void SetUp() override {
     auto mock_device_factory = std::make_unique<media::MockDeviceFactory>();
+    mock_device_factory_ = mock_device_factory.get();
     media::VideoCaptureDeviceDescriptor mock_descriptor;
     mock_descriptor.device_id = "MockDeviceId";
     mock_device_factory->AddMockDevice(&mock_device_, mock_descriptor);
 
     auto video_capture_system = std::make_unique<media::VideoCaptureSystemImpl>(
         std::move(mock_device_factory));
-    mock_device_factory_ = std::make_unique<DeviceFactoryMediaToMojoAdapter>(
+    service_device_factory_ = std::make_unique<DeviceFactoryMediaToMojoAdapter>(
         std::move(video_capture_system), base::DoNothing(),
         base::ThreadTaskRunnerHandle::Get());
-    source_provider_ =
-        std::make_unique<VideoSourceProviderImpl>(mock_device_factory_.get());
+    source_provider_ = std::make_unique<VideoSourceProviderImpl>(
+        service_device_factory_.get());
     source_provider_->SetServiceRef(service_keepalive_.CreateRef());
 
-    // Obtain the mock device backed source from |sourcr_provider_|.
+    // Obtain the mock device backed source from |source_provider_|.
     base::MockCallback<mojom::DeviceFactory::GetDeviceInfosCallback>
         device_infos_receiver;
     base::RunLoop wait_loop;
@@ -96,24 +98,40 @@
   }
 
   void LetClient2ConnectWithRequestableSettingsAndExpectToGetThem() {
+    LetClient2ConnectWithRequestableSettings(
+        false /*force_reopen_with_new_settings*/,
+        mojom::CreatePushSubscriptionResultCode::kCreatedWithRequestedSettings);
+  }
+
+  void LetClient2ConnectWithRequestableSettings(
+      bool force_reopen_with_new_settings,
+      mojom::CreatePushSubscriptionResultCode expected_result_code) {
     base::RunLoop run_loop;
     source_->CreatePushSubscription(
         std::move(receiver_2_), requestable_settings_,
-        false /*force_reopen_with_new_settings*/,
-        mojo::MakeRequest(&subscription_2_),
+        force_reopen_with_new_settings, mojo::MakeRequest(&subscription_2_),
         base::BindOnce(
             [](base::RunLoop* run_loop,
                media::VideoCaptureParams* requested_settings,
+               mojom::CreatePushSubscriptionResultCode expected_result_code,
                mojom::CreatePushSubscriptionResultCode result_code,
                const media::VideoCaptureParams&
                    settings_source_was_opened_with) {
-              ASSERT_EQ(mojom::CreatePushSubscriptionResultCode::
-                            kCreatedWithRequestedSettings,
-                        result_code);
-              ASSERT_EQ(*requested_settings, settings_source_was_opened_with);
+              ASSERT_EQ(expected_result_code, result_code);
+              if (expected_result_code ==
+                  mojom::CreatePushSubscriptionResultCode::
+                      kCreatedWithRequestedSettings) {
+                ASSERT_EQ(*requested_settings, settings_source_was_opened_with);
+              }
+              if (expected_result_code ==
+                  mojom::CreatePushSubscriptionResultCode::
+                      kCreatedWithDifferentSettings) {
+                ASSERT_FALSE(*requested_settings ==
+                             settings_source_was_opened_with);
+              }
               run_loop->Quit();
             },
-            &run_loop, &requestable_settings_));
+            &run_loop, &requestable_settings_, expected_result_code));
     run_loop.Run();
   }
 
@@ -145,7 +163,7 @@
 
     auto different_settings = requestable_settings_;
     // Change something arbitrary
-    different_settings.requested_format.frame_size = gfx::Size(123, 456);
+    different_settings.requested_format.frame_size = gfx::Size(124, 456);
     ASSERT_FALSE(requestable_settings_ == different_settings);
 
     source_->CreatePushSubscription(
@@ -190,6 +208,23 @@
     Mock::VerifyAndClearExpectations(&mock_receiver_2_);
   }
 
+  void SendFrameAndExpectToArriveOnlyAtSubscriber1() {
+    const int32_t kArbitraryFrameFeedbackId =
+        next_arbitrary_frame_feedback_id_++;
+    const int32_t kArbitraryRotation = 0;
+
+    base::RunLoop wait_loop;
+    EXPECT_CALL(mock_receiver_1_,
+                DoOnFrameReadyInBuffer(_, kArbitraryFrameFeedbackId, _, _))
+        .WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
+    EXPECT_CALL(mock_receiver_2_, DoOnFrameReadyInBuffer(_, _, _, _)).Times(0);
+    mock_device_.SendStubFrame(requestable_settings_.requested_format,
+                               kArbitraryRotation, kArbitraryFrameFeedbackId);
+    wait_loop.Run();
+    Mock::VerifyAndClearExpectations(&mock_receiver_1_);
+    Mock::VerifyAndClearExpectations(&mock_receiver_2_);
+  }
+
   void SendFrameAndExpectToArriveOnlyAtSubscriber2() {
     const int32_t kArbitraryFrameFeedbackId =
         next_arbitrary_frame_feedback_id_++;
@@ -210,7 +245,8 @@
  protected:
   base::test::ScopedTaskEnvironment task_environment_;
   media::MockDevice mock_device_;
-  std::unique_ptr<DeviceFactoryMediaToMojoAdapter> mock_device_factory_;
+  media::MockDeviceFactory* mock_device_factory_;
+  std::unique_ptr<DeviceFactoryMediaToMojoAdapter> service_device_factory_;
   std::unique_ptr<VideoSourceProviderImpl> source_provider_;
   mojom::VideoSourcePtr source_;
   media::VideoCaptureParams requestable_settings_;
@@ -242,6 +278,76 @@
 }
 
 TEST_F(MockVideoCaptureDeviceSharedAccessTest,
+       SecondClientsForcesReopenWithDifferentSettings) {
+  LetClient1ConnectWithRequestableSettingsAndExpectToGetThem();
+  subscription_1_->Activate();
+
+  auto previously_requested_settings = requestable_settings_;
+  // Change something arbitrary
+  requestable_settings_.requested_format.frame_size = gfx::Size(124, 456);
+  ASSERT_FALSE(requestable_settings_ == previously_requested_settings);
+
+  LetClient2ConnectWithRequestableSettings(
+      true /*force_reopen_with_new_settings*/,
+      mojom::CreatePushSubscriptionResultCode::kCreatedWithRequestedSettings);
+  subscription_2_->Activate();
+  SendFrameAndExpectToArriveAtBothSubscribers();
+}
+
+TEST_F(MockVideoCaptureDeviceSharedAccessTest,
+       SecondClientsForcesReopenWithSameSettings) {
+  LetClient1ConnectWithRequestableSettingsAndExpectToGetThem();
+  LetClient2ConnectWithRequestableSettings(
+      true /*force_reopen_with_new_settings*/,
+      mojom::CreatePushSubscriptionResultCode::kCreatedWithRequestedSettings);
+  subscription_1_->Activate();
+  subscription_2_->Activate();
+  SendFrameAndExpectToArriveAtBothSubscribers();
+}
+
+TEST_F(
+    MockVideoCaptureDeviceSharedAccessTest,
+    ExistingBuffersAreRetiredAndOnStartedIsNotSentAgainWhenDeviceIsReopened) {
+  LetClient1ConnectWithRequestableSettingsAndExpectToGetThem();
+  EXPECT_CALL(mock_receiver_1_, DoOnNewBuffer(_, _)).Times(1);
+  EXPECT_CALL(mock_receiver_1_, OnStarted()).Times(1);
+  subscription_1_->Activate();
+  mock_device_.SendOnStarted();
+  SendFrameAndExpectToArriveOnlyAtSubscriber1();
+  Mock::VerifyAndClearExpectations(&mock_receiver_1_);
+
+  auto previously_requested_settings = requestable_settings_;
+  // Change something arbitrary
+  requestable_settings_.requested_format.frame_size = gfx::Size(124, 456);
+  ASSERT_FALSE(requestable_settings_ == previously_requested_settings);
+
+  {
+    testing::InSequence s;
+    EXPECT_CALL(mock_receiver_1_, DoOnBufferRetired(_)).Times(1);
+    EXPECT_CALL(mock_receiver_1_, DoOnNewBuffer(_, _)).Times(1);
+  }
+  EXPECT_CALL(mock_receiver_1_, OnStarted()).Times(0);
+
+  LetClient2ConnectWithRequestableSettings(
+      true /*force_reopen_with_new_settings*/,
+      mojom::CreatePushSubscriptionResultCode::kCreatedWithRequestedSettings);
+  subscription_2_->Activate();
+
+  mock_device_.SendOnStarted();
+  SendFrameAndExpectToArriveAtBothSubscribers();
+}
+
+TEST_F(MockVideoCaptureDeviceSharedAccessTest,
+       CreatingSubscriptionFailsWhenCreatingDeviceFails) {
+  // Make it so that attempts to open the mock device will fail.
+  mock_device_factory_->RemoveAllDevices();
+
+  LetClient2ConnectWithRequestableSettings(
+      false /*force_reopen_with_new_settings*/,
+      mojom::CreatePushSubscriptionResultCode::kFailed);
+}
+
+TEST_F(MockVideoCaptureDeviceSharedAccessTest,
        NoFramesArePushedUntilSubscriptionIsActivated) {
   LetTwoClientsConnectWithSameSettingsOneByOne();
 
diff --git a/services/video_capture/texture_virtual_device_mojo_adapter.cc b/services/video_capture/texture_virtual_device_mojo_adapter.cc
index 07d64cc..2a45c4f 100644
--- a/services/video_capture/texture_virtual_device_mojo_adapter.cc
+++ b/services/video_capture/texture_virtual_device_mojo_adapter.cc
@@ -118,18 +118,21 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-void TextureVirtualDeviceMojoAdapter::Stop() {
+void TextureVirtualDeviceMojoAdapter::Stop(StopCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!receiver_.is_bound())
+  if (!receiver_.is_bound()) {
+    std::move(callback).Run();
     return;
+  }
   // Unsubscribe from connection error callbacks.
   receiver_.set_connection_error_handler(base::OnceClosure());
   receiver_.reset();
+  std::move(callback).Run();
 }
 
 void TextureVirtualDeviceMojoAdapter::OnReceiverConnectionErrorOrClose() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  Stop();
+  Stop(base::DoNothing());
   if (optional_receiver_disconnected_callback_)
     std::move(optional_receiver_disconnected_callback_).Run();
 }
diff --git a/services/video_capture/texture_virtual_device_mojo_adapter.h b/services/video_capture/texture_virtual_device_mojo_adapter.h
index 0381730..16a7de6 100644
--- a/services/video_capture/texture_virtual_device_mojo_adapter.h
+++ b/services/video_capture/texture_virtual_device_mojo_adapter.h
@@ -46,8 +46,7 @@
   void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
                        SetPhotoOptionsCallback callback) override;
   void TakePhoto(TakePhotoCallback callback) override;
-
-  void Stop();
+  void Stop(StopCallback callback) override;
 
  private:
   void OnReceiverConnectionErrorOrClose();
diff --git a/services/video_capture/video_source_impl.cc b/services/video_capture/video_source_impl.cc
index 000a705..742b1e25 100644
--- a/services/video_capture/video_source_impl.cc
+++ b/services/video_capture/video_source_impl.cc
@@ -18,6 +18,7 @@
       device_id_(device_id),
       on_last_binding_closed_cb_(std::move(on_last_binding_closed_cb)),
       device_status_(DeviceStatus::kNotStarted),
+      restart_device_once_when_stop_complete_(false),
       weak_factory_(this) {
   bindings_.set_connection_error_handler(base::BindRepeating(
       &VideoSourceImpl::OnClientDisconnected, base::Unretained(this)));
@@ -37,10 +38,6 @@
     bool force_reopen_with_new_settings,
     mojom::PushVideoStreamSubscriptionRequest subscription_request,
     CreatePushSubscriptionCallback callback) {
-  if (force_reopen_with_new_settings) {
-    NOTIMPLEMENTED();
-    return;
-  }
   auto subscription = std::make_unique<PushVideoStreamSubscriptionImpl>(
       std::move(subscription_request), std::move(subscriber),
       requested_settings, std::move(callback), &broadcaster_, &device_);
@@ -52,20 +49,28 @@
       std::make_pair(subscription.get(), std::move(subscription)));
   switch (device_status_) {
     case DeviceStatus::kNotStarted:
-      device_start_settings_ = requested_settings;
-      device_status_ = DeviceStatus::kStartingAsynchronously;
-      device_factory_->CreateDevice(
-          device_id_, mojo::MakeRequest(&device_),
-          base::BindOnce(&VideoSourceImpl::OnCreateDeviceResponse,
-                         weak_factory_.GetWeakPtr()));
+      StartDeviceWithSettings(requested_settings);
       return;
     case DeviceStatus::kStartingAsynchronously:
-      // No need to do anything. Response will be sent when
+      if (force_reopen_with_new_settings)
+        device_start_settings_ = requested_settings;
+      // No need to do anything else. Response will be sent when
       // OnCreateDeviceResponse() gets called.
       return;
     case DeviceStatus::kStarted:
-      subscription_ptr->NotifySubscriberCreateSubscriptionSucceededWithSettings(
-          device_start_settings_);
+      if (!force_reopen_with_new_settings ||
+          requested_settings == device_start_settings_) {
+        subscription_ptr->OnDeviceStartSucceededWithSettings(
+            device_start_settings_);
+        return;
+      }
+      restart_device_once_when_stop_complete_ = true;
+      device_start_settings_ = requested_settings;
+      StopDeviceAsynchronously();
+      return;
+    case DeviceStatus::kStoppingAsynchronously:
+      restart_device_once_when_stop_complete_ = true;
+      device_start_settings_ = requested_settings;
       return;
   }
 }
@@ -78,6 +83,16 @@
   }
 }
 
+void VideoSourceImpl::StartDeviceWithSettings(
+    const media::VideoCaptureParams& requested_settings) {
+  device_start_settings_ = requested_settings;
+  device_status_ = DeviceStatus::kStartingAsynchronously;
+  device_factory_->CreateDevice(
+      device_id_, mojo::MakeRequest(&device_),
+      base::BindOnce(&VideoSourceImpl::OnCreateDeviceResponse,
+                     weak_factory_.GetWeakPtr()));
+}
+
 void VideoSourceImpl::OnCreateDeviceResponse(
     mojom::DeviceAccessResultCode result_code) {
   switch (result_code) {
@@ -89,12 +104,12 @@
                      std::move(broadcaster_as_receiver));
       device_status_ = DeviceStatus::kStarted;
       if (push_subscriptions_.empty()) {
-        StopDevice();
+        StopDeviceAsynchronously();
         return;
       }
       for (auto& entry : push_subscriptions_) {
         auto& subscription = entry.second;
-        subscription->NotifySubscriberCreateSubscriptionSucceededWithSettings(
+        subscription->OnDeviceStartSucceededWithSettings(
             device_start_settings_);
       }
       return;
@@ -103,7 +118,7 @@
     case mojom::DeviceAccessResultCode::NOT_INITIALIZED:
       for (auto& entry : push_subscriptions_) {
         auto& subscription = entry.second;
-        subscription->NotifySubscriberCreateSubscriptionFailed();
+        subscription->OnDeviceStartFailed();
       }
       push_subscriptions_.clear();
       device_status_ = DeviceStatus::kNotStarted;
@@ -128,16 +143,29 @@
         // are any subscriptions.
         break;
       case DeviceStatus::kStarted:
-        StopDevice();
+        StopDeviceAsynchronously();
+        break;
+      case DeviceStatus::kStoppingAsynchronously:
+        // Nothing to do here.
         break;
     }
   }
   std::move(done_cb).Run();
 }
 
-void VideoSourceImpl::StopDevice() {
+void VideoSourceImpl::StopDeviceAsynchronously() {
+  device_->Stop(base::BindOnce(&VideoSourceImpl::OnStopDeviceComplete,
+                               weak_factory_.GetWeakPtr()));
+  device_status_ = DeviceStatus::kStoppingAsynchronously;
+}
+
+void VideoSourceImpl::OnStopDeviceComplete() {
   device_.reset();
   device_status_ = DeviceStatus::kNotStarted;
+  if (!restart_device_once_when_stop_complete_)
+    return;
+  restart_device_once_when_stop_complete_ = false;
+  StartDeviceWithSettings(device_start_settings_);
 }
 
 }  // namespace video_capture
diff --git a/services/video_capture/video_source_impl.h b/services/video_capture/video_source_impl.h
index 70519d6..16e80f2 100644
--- a/services/video_capture/video_source_impl.h
+++ b/services/video_capture/video_source_impl.h
@@ -40,14 +40,18 @@
     kNotStarted,
     kStartingAsynchronously,
     kStarted,
+    kStoppingAsynchronously
   };
 
   void OnClientDisconnected();
+  void StartDeviceWithSettings(
+      const media::VideoCaptureParams& requested_settings);
   void OnCreateDeviceResponse(mojom::DeviceAccessResultCode result_code);
   void OnPushSubscriptionClosedOrDisconnectedOrDiscarded(
       PushVideoStreamSubscriptionImpl* subscription,
       base::OnceClosure done_cb);
-  void StopDevice();
+  void StopDeviceAsynchronously();
+  void OnStopDeviceComplete();
 
   mojom::DeviceFactory* const device_factory_;
   const std::string device_id_;
@@ -63,6 +67,7 @@
   DeviceStatus device_status_;
   mojom::DevicePtr device_;
   media::VideoCaptureParams device_start_settings_;
+  bool restart_device_once_when_stop_complete_;
 
   base::WeakPtrFactory<VideoSourceImpl> weak_factory_;
 
diff --git a/services/video_capture/virtual_device_enabled_device_factory.cc b/services/video_capture/virtual_device_enabled_device_factory.cc
index 7f46a59..3448093 100644
--- a/services/video_capture/virtual_device_enabled_device_factory.cc
+++ b/services/video_capture/virtual_device_enabled_device_factory.cc
@@ -59,9 +59,9 @@
 
   void StopDevice() {
     if (shared_memory_device_)
-      shared_memory_device_->Stop();
+      shared_memory_device_->Stop(base::DoNothing());
     else
-      texture_device_->Stop();
+      texture_device_->Stop(base::DoNothing());
   }
 
   media::VideoCaptureDeviceInfo device_info() const { return device_info_; }
diff --git a/services/viz/public/cpp/compositing/render_pass_struct_traits.h b/services/viz/public/cpp/compositing/render_pass_struct_traits.h
index b7ebce48..0e8c827 100644
--- a/services/viz/public/cpp/compositing/render_pass_struct_traits.h
+++ b/services/viz/public/cpp/compositing/render_pass_struct_traits.h
@@ -13,6 +13,7 @@
 #include "services/viz/public/cpp/compositing/quads_struct_traits.h"
 #include "services/viz/public/interfaces/compositing/render_pass.mojom-shared.h"
 #include "ui/gfx/ipc/color/gfx_param_traits.h"
+#include "ui/gfx/mojo/rrect_f_struct_traits.h"
 #include "ui/gfx/mojo/transform_struct_traits.h"
 
 namespace mojo {
@@ -50,7 +51,7 @@
     return input->backdrop_filters;
   }
 
-  static const gfx::RectF& backdrop_filter_bounds(
+  static const gfx::RRectF& backdrop_filter_bounds(
       const std::unique_ptr<viz::RenderPass>& input) {
     return input->backdrop_filter_bounds;
   }
diff --git a/services/viz/public/cpp/compositing/struct_traits_perftest.cc b/services/viz/public/cpp/compositing/struct_traits_perftest.cc
index 10590616e..421beb9 100644
--- a/services/viz/public/cpp/compositing/struct_traits_perftest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_perftest.cc
@@ -155,6 +155,8 @@
     gfx::Size arbitrary_size1(15, 19);
     gfx::Size arbitrary_size2(3, 99);
     gfx::RectF arbitrary_rectf1(4.2f, -922.1f, 15.6f, 29.5f);
+    gfx::RRectF arbitrary_rrectf1(4.2f, -922.1f, 15.6f, 29.5f, 1.2f, 2.3f, 3.4f,
+                                  4.5f, 5.6f, 6.7f, 7.8f, 8.9f);
     gfx::PointF arbitrary_pointf1(31.4f, 15.9f);
     gfx::PointF arbitrary_pointf2(26.5f, -35.8f);
     float arbitrary_float1 = 0.7f;
@@ -199,7 +201,7 @@
     std::unique_ptr<RenderPass> pass_in = RenderPass::Create();
     pass_in->SetAll(root_id, arbitrary_rect1, arbitrary_rect2,
                     arbitrary_matrix1, arbitrary_filters2, arbitrary_filters1,
-                    arbitrary_rectf1, arbitrary_color_space, arbitrary_bool1,
+                    arbitrary_rrectf1, arbitrary_color_space, arbitrary_bool1,
                     arbitrary_bool1, arbitrary_bool1, arbitrary_bool1);
 
     // Texture quads
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 56534d7..e1921d0 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -741,7 +741,8 @@
   backdrop_filters.Append(cc::FilterOperation::CreateSaturateFilter(4.f));
   backdrop_filters.Append(cc::FilterOperation::CreateZoomFilter(2.0f, 1));
   backdrop_filters.Append(cc::FilterOperation::CreateSaturateFilter(2.f));
-  gfx::RectF backdrop_filter_bounds = gfx::RectF(10, 20, 130, 140);
+  gfx::RRectF backdrop_filter_bounds =
+      gfx::RRectF(10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8);
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
   const bool has_transparent_background = true;
   const bool cache_render_pass = true;
@@ -811,8 +812,7 @@
   EXPECT_EQ(has_transparent_background, output->has_transparent_background);
   EXPECT_EQ(filters, output->filters);
   EXPECT_EQ(backdrop_filters, output->backdrop_filters);
-  EXPECT_EQ(gfx::ToNearestRect(backdrop_filter_bounds),
-            gfx::ToNearestRect(output->backdrop_filter_bounds));
+  EXPECT_EQ(backdrop_filter_bounds, output->backdrop_filter_bounds);
   EXPECT_EQ(cache_render_pass, output->cache_render_pass);
   EXPECT_EQ(has_damage_from_contributing_content,
             output->has_damage_from_contributing_content);
@@ -888,7 +888,7 @@
   const bool generate_mipmap = false;
   std::unique_ptr<RenderPass> input = RenderPass::Create();
   input->SetAll(render_pass_id, output_rect, damage_rect, transform_to_root,
-                cc::FilterOperations(), cc::FilterOperations(), gfx::RectF(),
+                cc::FilterOperations(), cc::FilterOperations(), gfx::RRectF(),
                 color_space, has_transparent_background, cache_render_pass,
                 has_damage_from_contributing_content, generate_mipmap);
 
diff --git a/services/viz/public/interfaces/compositing/render_pass.mojom b/services/viz/public/interfaces/compositing/render_pass.mojom
index df4588bf..9108e9f 100644
--- a/services/viz/public/interfaces/compositing/render_pass.mojom
+++ b/services/viz/public/interfaces/compositing/render_pass.mojom
@@ -9,6 +9,7 @@
 import "services/viz/public/interfaces/compositing/quads.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/gfx/mojo/color_space.mojom";
+import "ui/gfx/mojo/rrect_f.mojom";
 import "ui/gfx/mojo/transform.mojom";
 
 // See components/viz/common/quads/render_pass.h.
@@ -19,7 +20,7 @@
   gfx.mojom.Transform transform_to_root_target;
   FilterOperations filters;
   FilterOperations backdrop_filters;
-  gfx.mojom.RectF backdrop_filter_bounds;
+  gfx.mojom.RRectF backdrop_filter_bounds;
   gfx.mojom.ColorSpace color_space;
   bool has_transparent_background;
   bool cache_render_pass = false;
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 7f0c2c8..1c0307d 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -390,9 +390,9 @@
               "pool": "Chrome-CrOS-VM"
             }
           ],
-          "hard_timeout": 2400,
+          "hard_timeout": 1200,
           "idempotent": false,
-          "shards": 12
+          "shards": 24
         }
       }
     ]
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index cec9545f..0974db2 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -2013,8 +2013,7 @@
       },
       {
         "args": [
-          "--enable-features=NetworkService",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/mojo.fyi.chromeos.network_interactive_ui_tests.filter"
+          "--enable-features=NetworkService"
         ],
         "name": "network_service_interactive_ui_tests",
         "swarming": {
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index d048959..14ac270 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -5366,6 +5366,516 @@
       }
     ]
   },
+  "Linux FYI Experimental Release (Intel HD 630)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "angle_end2end_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0",
+          "--no-xvfb"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "angle_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-retry-limit=0"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "angle_white_box_tests"
+      },
+      {
+        "args": [
+          "--enable-gpu",
+          "--test-launcher-bot-mode",
+          "--test-launcher-jobs=1",
+          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*",
+          "--no-xvfb"
+        ],
+        "name": "tab_capture_end2end_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "dawn_end2end_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=validating"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--no-xvfb"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gl_unittests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        },
+        "test": "swiftshader_unittests"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "context_lost",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "context_lost_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "depth_capture",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "depth_capture_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "gpu_process",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "gpu_process_launch_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "hardware_accelerated_feature_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "info_collection",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--expected-vendor-id",
+          "8086",
+          "--expected-device-id",
+          "5912"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "info_collection_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "maps",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "linux",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "maps_pixel_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--refimg-cloud-storage-bucket",
+          "chromium-gpu-archive/reference-images",
+          "--os-type",
+          "linux",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "pixel_test",
+        "non_precommit_args": [
+          "--upload-refimg-to-cloud-storage"
+        ],
+        "precommit_args": [
+          "--download-refimg-from-cloud-storage"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "screenshot_sync",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "screenshot_sync_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "trace_test",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "trace_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "webgl2_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "webgl2_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "webgl_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "webgl_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-18.0.5",
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "shards": 2
+        }
+      }
+    ]
+  },
   "Linux FYI Experimental Release (NVIDIA)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index d75dcf9..ded4b8b1 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -77,7 +77,6 @@
 
   data = [
     "//testing/buildbot/filters/chromeos.mash.fyi.interactive_ui_tests.filter",
-    "//testing/buildbot/filters/mojo.fyi.chromeos.network_interactive_ui_tests.filter",
     "//testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter",
   ]
 }
diff --git a/testing/buildbot/filters/mojo.fyi.chromeos.network_interactive_ui_tests.filter b/testing/buildbot/filters/mojo.fyi.chromeos.network_interactive_ui_tests.filter
deleted file mode 100644
index 2d64bed..0000000
--- a/testing/buildbot/filters/mojo.fyi.chromeos.network_interactive_ui_tests.filter
+++ /dev/null
@@ -1,25 +0,0 @@
-# NOTE: if adding an exclusion for an existing failure (e.g. additional test for
-# feature X that is already not working), please add it beside the existing
-# failures. Otherwise please reach out to network-service-dev@.
-
-# This filter contains Chrome OS only test failures.
-# See https://crbug.com/881976
-
-# Uncategorized timeouts or test failures.
--DownloadNotificationTest.CancelDownload
--DownloadNotificationTest.CloseNotificationAfterDownload
--DownloadNotificationTest.CloseNotificationWhileDownloading
--DownloadNotificationTest.DownloadCancelledByUserExternally
--DownloadNotificationTest.DownloadFile
--DownloadNotificationTest.DownloadMultipleFiles
--DownloadNotificationTest.DownloadMultipleFilesOneByOne
--DownloadNotificationTest.DownloadRemoved
--DownloadNotificationTest.IncognitoDownloadFile
--DownloadNotificationTest.InterruptDownload
--DownloadNotificationTest.InterruptDownloadAfterClosingNotification
--DownloadNotificationTest.SimultaneousIncognitoAndNormalDownloads
--MultiProfileDownloadNotificationTest.DownloadMultipleFiles
-
-# NOTE: if adding an exclusion for an existing failure (e.g. additional test for
-# feature X that is already not working), please add it beside the existing
-# failures. Otherwise please reach out to network-service-dev@.
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index 425a15c..7a4e313 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -255,6 +255,16 @@
       }
     }
   },
+  'linux_intel_hd_630_experimental': {
+    # Similar to stable, but with a newer Mesa version.
+    'swarming': {
+      'dimensions': {
+        'gpu': '8086:5912-18.0.5',
+        'os': 'Ubuntu',
+        'pool': 'Chrome-GPU',
+      },
+    },
+  },
   'linux_nvidia_quadro_p400': {
     'swarming': {
       'dimensions': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 4ff4678..f4f24f9 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -495,9 +495,9 @@
           '--remote-ssh-port=9222',
         ],
         'swarming': {
-          'hard_timeout': 2400,
+          'hard_timeout': 1200,
           'idempotent': False,  # https://crbug.com/549140
-          'shards': 12,
+          'shards': 24,
         },
       },
     },
@@ -3924,7 +3924,6 @@
       'network_service_interactive_ui_tests': {
         'args': [
           '--enable-features=NetworkService',
-          '--test-launcher-filter-file=../../testing/buildbot/filters/mojo.fyi.chromeos.network_interactive_ui_tests.filter',
         ],
         'swarming': {
           'shards': 3,
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 8e828dc..6b5d1ab 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2258,6 +2258,17 @@
           'gpu_telemetry_tests': 'gpu_fyi_win_and_linux_telemetry_tests',
         },
       },
+      'Linux FYI Experimental Release (Intel HD 630)': {
+        'os_type': 'linux',
+        'browser_config': 'release',
+        'mixins': [
+          'linux_intel_hd_630_experimental',
+        ],
+        'test_suites': {
+          'gtest_tests': 'gpu_fyi_linux_release_gtests',
+          'gpu_telemetry_tests': 'gpu_fyi_linux_intel_and_nvidia_release_telemetry_tests',
+        }
+      },
       'Linux FYI Experimental Release (NVIDIA)': {
         'os_type': 'linux',
         'browser_config': 'release',
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 5745fa1..4d934bda 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -143,7 +143,9 @@
     "platform/modules/mediastream/media_stream_audio_deliverer.h",
     "platform/modules/mediastream/media_stream_audio_source.h",
     "platform/modules/mediastream/media_stream_audio_track.h",
+    "platform/modules/mediastream/media_stream_types.h",
     "platform/modules/mediastream/platform_media_stream_source.h",
+    "platform/modules/mediastream/secure_display_link_tracker.h",
     "platform/modules/mediastream/web_media_stream_audio_sink.h",
     "platform/modules/mediastream/web_media_stream_sink.h",
     "platform/modules/mediastream/web_platform_media_stream_track.h",
@@ -545,6 +547,7 @@
     "//cc:cc",
     "//cc/paint:paint",
     "//components/viz/common",
+    "//media/capture:capture_base",
     "//mojo/public/cpp/bindings:bindings",
     "//mojo/public/cpp/system:system",
     "//services/device/public/mojom:mojom_shared_cpp_sources",
diff --git a/third_party/blink/public/platform/modules/mediastream/DEPS b/third_party/blink/public/platform/modules/mediastream/DEPS
index 99c6905..53f0924b 100644
--- a/third_party/blink/public/platform/modules/mediastream/DEPS
+++ b/third_party/blink/public/platform/modules/mediastream/DEPS
@@ -4,4 +4,5 @@
     "+base/stl_util.h",
 
     "+media/base",
+    "+media/capture",
 ]
diff --git a/third_party/blink/public/platform/modules/mediastream/media_stream_types.h b/third_party/blink/public/platform/modules/mediastream/media_stream_types.h
new file mode 100644
index 0000000..30ddbc7
--- /dev/null
+++ b/third_party/blink/public/platform/modules/mediastream/media_stream_types.h
@@ -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.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_MEDIA_STREAM_TYPES_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_MEDIA_STREAM_TYPES_H_
+
+#include "media/capture/video_capture_types.h"
+
+namespace blink {
+
+using VideoTrackSettingsCallback =
+    base::RepeatingCallback<void(gfx::Size frame_size, double frame_rate)>;
+
+using VideoTrackFormatCallback =
+    base::RepeatingCallback<void(const media::VideoCaptureFormat&)>;
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_MEDIA_STREAM_TYPES_H_
diff --git a/content/renderer/media/stream/secure_display_link_tracker.h b/third_party/blink/public/platform/modules/mediastream/secure_display_link_tracker.h
similarity index 82%
rename from content/renderer/media/stream/secure_display_link_tracker.h
rename to third_party/blink/public/platform/modules/mediastream/secure_display_link_tracker.h
index 0b00380..50742ac 100644
--- a/content/renderer/media/stream/secure_display_link_tracker.h
+++ b/third_party/blink/public/platform/modules/mediastream/secure_display_link_tracker.h
@@ -2,14 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_MEDIA_STREAM_SECURE_DISPLAY_LINK_TRACKER_H_
-#define CONTENT_RENDERER_MEDIA_STREAM_SECURE_DISPLAY_LINK_TRACKER_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_SECURE_DISPLAY_LINK_TRACKER_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_SECURE_DISPLAY_LINK_TRACKER_H_
 
 #include <algorithm>
 #include <vector>
 
 #include "base/stl_util.h"
 
+namespace blink {
+
 // Tracks all connected links (video sinks / tracks), and reports if they are
 // all secure for video capturing.
 template <typename T>
@@ -56,4 +58,6 @@
   Add(link, is_link_secure);
 }
 
-#endif  // CONTENT_RENDERER_MEDIA_STREAM_SECURE_DISPLAY_LINK_TRACKER_H_
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_MEDIASTREAM_SECURE_DISPLAY_LINK_TRACKER_H_
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc b/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
index c50c77d..7cbc75cf 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
@@ -8,19 +8,31 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_response.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
 #include "third_party/blink/renderer/core/fetch/fetch_data_loader.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata.h"
+#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
+#include "third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
 namespace {
 
+// Wasm only has a single metadata type, but we need to tag it.
+static const int kWasmModuleTag = 1;
+
 // The |FetchDataLoader| for streaming compilation of WebAssembly code. The
 // received bytes get forwarded to the V8 API class |WasmStreaming|.
 class FetchDataLoaderForWasmStreaming final : public FetchDataLoader,
@@ -28,10 +40,12 @@
   USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderForWasmStreaming);
 
  public:
-  FetchDataLoaderForWasmStreaming(ScriptState* script_state,
-                                  std::shared_ptr<v8::WasmStreaming> streaming)
+  FetchDataLoaderForWasmStreaming(std::shared_ptr<v8::WasmStreaming> streaming,
+                                  ScriptState* script_state)
       : streaming_(std::move(streaming)), script_state_(script_state) {}
 
+  v8::WasmStreaming* streaming() const { return streaming_.get(); }
+
   void Start(BytesConsumer* consumer,
              FetchDataLoader::Client* client) override {
     DCHECK(!consumer_);
@@ -112,7 +126,8 @@
       streaming_->Abort(v8::Local<v8::Value>());
     }
   }
-  TraceWrapperMember<BytesConsumer> consumer_;
+
+  Member<BytesConsumer> consumer_;
   Member<FetchDataLoader::Client> client_;
   std::shared_ptr<v8::WasmStreaming> streaming_;
   const Member<ScriptState> script_state_;
@@ -167,8 +182,87 @@
   ExceptionState& exception_state_;
 };
 
+SingleCachedMetadataHandler* GetCachedMetadataHandler(ScriptState* script_state,
+                                                      const KURL& url) {
+  if (!RuntimeEnabledFeatures::WasmCodeCacheEnabled())
+    return nullptr;
+  ExecutionContext* execution_context = ExecutionContext::From(script_state);
+  if (!execution_context)
+    return nullptr;
+  ResourceFetcher* fetcher = execution_context->Fetcher();
+  if (!fetcher)
+    return nullptr;
+  if (!url.IsValid())
+    return nullptr;
+  Resource* resource = fetcher->CachedResource(url);
+  if (!resource)
+    return nullptr;
+
+  // Wasm modules should be fetched as raw resources.
+  DCHECK_EQ(ResourceType::kRaw, resource->GetType());
+  RawResource* raw_resource = ToRawResource(resource);
+  return raw_resource->ScriptCacheHandler();
+}
+
+class WasmStreamingClient : public v8::WasmStreaming::Client {
+ public:
+  WasmStreamingClient(const KURL& url,
+                      v8::Isolate* isolate,
+                      v8::Local<v8::Context> context)
+      : url_(url), isolate_(isolate), context_(isolate, context) {
+    context_.SetWeak();
+  }
+
+  void OnModuleCompiled(v8::CompiledWasmModule compiled_module) override {
+    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+                         "v8.wasm.compiledModule", TRACE_EVENT_SCOPE_THREAD,
+                         "url", url_.GetString().Utf8());
+
+    // Don't cache if Context has been destroyed.
+    if (context_.IsEmpty())
+      return;
+
+    v8::HandleScope handle_scope(isolate_);
+    auto context = context_.Get(isolate_);
+    ScriptState* script_state = ScriptState::From(context);
+    SingleCachedMetadataHandler* cache_handler =
+        GetCachedMetadataHandler(script_state, url_);
+    if (!cache_handler)
+      return;
+
+    v8::MemorySpan<const uint8_t> wire_bytes =
+        compiled_module.GetWireBytesRef();
+    // Our heuristic for whether it's worthwhile to cache is that the module
+    // was fully compiled and it is "large". Wire bytes size is likely to be
+    // highly correlated with compiled module size so we use it to avoid the
+    // cost of serializing when not caching.
+    const size_t kWireBytesSizeThresholdBytes = 1UL << 17;  // 128 KB.
+    if (wire_bytes.size() < kWireBytesSizeThresholdBytes)
+      return;
+
+    v8::OwnedBuffer serialized_module = compiled_module.Serialize();
+    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+                         "v8.wasm.cachedModule", TRACE_EVENT_SCOPE_THREAD,
+                         "producedCacheSize", serialized_module.size);
+    cache_handler->SetCachedMetadata(
+        kWasmModuleTag,
+        reinterpret_cast<const uint8_t*>(serialized_module.buffer.get()),
+        serialized_module.size);
+  }
+
+ private:
+  KURL url_;
+  v8::Isolate* isolate_;
+  v8::Global<v8::Context> context_;
+
+  DISALLOW_COPY_AND_ASSIGN(WasmStreamingClient);
+};
+
 void StreamFromResponseCallback(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
+  TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+                       "v8.wasm.streamFromResponseCallback",
+                       TRACE_EVENT_SCOPE_THREAD);
   ExceptionState exception_state(args.GetIsolate(),
                                  ExceptionState::kExecutionContext,
                                  "WebAssembly", "compile");
@@ -224,9 +318,35 @@
     return;
   }
 
+  KURL url(response->url());
+  SingleCachedMetadataHandler* cache_handler =
+      GetCachedMetadataHandler(script_state, url);
+  if (cache_handler) {
+    streaming->SetClient(std::make_shared<WasmStreamingClient>(
+        url, args.GetIsolate(), script_state->GetContext()));
+    scoped_refptr<CachedMetadata> cached_module =
+        cache_handler->GetCachedMetadata(kWasmModuleTag);
+    if (cached_module) {
+      TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+                           "v8.wasm.moduleCacheHit", TRACE_EVENT_SCOPE_THREAD,
+                           "url", url.GetString().Utf8(), "consumedCacheSize",
+                           cached_module->size());
+      bool is_valid = streaming->SetCompiledModuleBytes(
+          reinterpret_cast<const uint8_t*>(cached_module->Data()),
+          cached_module->size());
+      if (!is_valid) {
+        TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+                             "v8.wasm.moduleCacheInvalid",
+                             TRACE_EVENT_SCOPE_THREAD);
+        cache_handler->ClearCachedMetadata(
+            CachedMetadataHandler::kSendToPlatform);
+      }
+    }
+  }
+
   FetchDataLoaderForWasmStreaming* loader =
-      MakeGarbageCollected<FetchDataLoaderForWasmStreaming>(script_state,
-                                                            streaming);
+      MakeGarbageCollected<FetchDataLoaderForWasmStreaming>(streaming,
+                                                            script_state);
   response->BodyBuffer()->StartLoading(
       loader, MakeGarbageCollected<WasmDataLoaderClient>(), exception_state);
 }
diff --git a/third_party/blink/renderer/core/OWNERS b/third_party/blink/renderer/core/OWNERS
index 80e3fa5..9dc32a8 100644
--- a/third_party/blink/renderer/core/OWNERS
+++ b/third_party/blink/renderer/core/OWNERS
@@ -9,6 +9,7 @@
 bokan@chromium.org
 cbiesinger@chromium.org
 chrishtr@chromium.org
+clamy@chromium.org
 dcheng@chromium.org
 # dtapuska reviews input-related changes
 dtapuska@chromium.org
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index bc4689e7..7aa570a 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -49,6 +49,7 @@
                                        ExecutionContext* context)
     : ContextLifecycleObserver(context),
       element_(element),
+      state_(this),
       weak_factory_(this) {
   DCHECK(element_->GetDocument().View());
   element_->GetDocument().View()->RegisterForLifecycleNotifications(this);
@@ -106,6 +107,11 @@
   double timeout_ms = (options && options->hasTimeout())
                           ? options->timeout()
                           : kDefaultLockTimeoutMs;
+
+  // TODO(vmpstr): IMPORTANT. When searchability changes, we might need to
+  // adjust the count of activation blocking locks we keep on the document
+  // object.
+
   // We always reschedule a timeout task even if we're not starting a new
   // acquire. The reason for this is that the last acquire dictates the timeout
   // interval. Note that the following call cancels any existing timeout tasks.
@@ -324,7 +330,7 @@
 bool DisplayLockContext::IsSearchable() const {
   // TODO(vmpstr): Support "searchable: true" option, which allows locked
   // elements to be searched.
-  return state_ == kUnlocked;
+  return !IsLocked();
 }
 
 void DisplayLockContext::DidAttachLayoutTree() {
@@ -527,12 +533,23 @@
 }
 
 void DisplayLockContext::DidMoveToNewDocument(Document& old_document) {
+  DCHECK(element_);
+
   // Since we're observing the lifecycle updates, ensure that we listen to the
   // right document's view.
   if (old_document.View())
     old_document.View()->UnregisterFromLifecycleNotifications(this);
-  if (element_ && element_->GetDocument().View())
+  if (element_->GetDocument().View())
     element_->GetDocument().View()->RegisterForLifecycleNotifications(this);
+
+  if (!IsSearchable()) {
+    old_document.RemoveActivationBlockingDisplayLock();
+    element_->GetDocument().AddActivationBlockingDisplayLock();
+  }
+  if (IsLocked()) {
+    old_document.RemoveLockedDisplayLock();
+    element_->GetDocument().AddLockedDisplayLock();
+  }
 }
 
 void DisplayLockContext::WillStartLifecycleUpdate() {
@@ -611,6 +628,15 @@
   }
 }
 
+void DisplayLockContext::ElementWasDestroyed(Document& document) {
+  // Since the element is destroyed, this is the last chance we get to adjust
+  // our lock counts.
+  if (!IsSearchable())
+    document.RemoveActivationBlockingDisplayLock();
+  if (IsLocked())
+    document.RemoveLockedDisplayLock();
+}
+
 void DisplayLockContext::ScheduleAnimation() {
   DCHECK(element_->isConnected());
 
@@ -695,4 +721,42 @@
     context_->NotifyForcedUpdateScopeEnded();
 }
 
+// StateChangeHelper implementation
+// -----------------------------------------------
+DisplayLockContext::StateChangeHelper::StateChangeHelper(
+    DisplayLockContext* context)
+    : context_(context) {}
+
+DisplayLockContext::StateChangeHelper& DisplayLockContext::StateChangeHelper::
+operator=(State new_state) {
+  if (new_state == state_)
+    return *this;
+
+  bool was_searchable = context_->IsSearchable();
+  bool was_locked = context_->IsLocked();
+
+  state_ = new_state;
+
+  if (!context_->element_)
+    return *this;
+
+  // Adjust the total number of locked display locks.
+  auto& document = context_->element_->GetDocument();
+  if (context_->IsLocked() != was_locked) {
+    if (was_locked)
+      document.RemoveLockedDisplayLock();
+    else
+      document.AddLockedDisplayLock();
+  }
+
+  // Adjust activation blocking lock counts.
+  if (context_->IsSearchable() != was_searchable) {
+    if (was_searchable)
+      document.AddActivationBlockingDisplayLock();
+    else
+      document.RemoveActivationBlockingDisplayLock();
+  }
+  return *this;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h
index a5c0d38..f039914 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -111,6 +111,10 @@
   // for find-in-page and tab order.
   bool IsSearchable() const;
 
+  // Returns true if this lock is locked. Note from the outside perspective, the
+  // lock is locked any time the state is not kUnlocked.
+  bool IsLocked() const { return state_ != kUnlocked; }
+
   // Called when the layout tree is attached. This is used to verify
   // containment.
   void DidAttachLayoutTree();
@@ -138,6 +142,11 @@
   void WillStartLifecycleUpdate() override;
   void DidFinishLifecycleUpdate() override;
 
+  // Called when the element associated with this lock is destroyed. Note that
+  // because the lifetime of this lock is independent of the element, this can
+  // happen.
+  void ElementWasDestroyed(Document&);
+
  private:
   friend class DisplayLockContextTest;
   friend class DisplayLockSuspendedHandle;
@@ -152,6 +161,18 @@
     kPendingAcquire,
   };
 
+  class StateChangeHelper {
+   public:
+    StateChangeHelper(DisplayLockContext*);
+
+    operator State() const { return state_; }
+    StateChangeHelper& operator=(State);
+
+   private:
+    State state_ = kUnlocked;
+    UntracedMember<DisplayLockContext> context_;
+  };
+
   // Initiate a commit.
   void StartCommit();
   // Initiate an update.
@@ -215,7 +236,7 @@
   Member<ScriptPromiseResolver> acquire_resolver_;
   WeakMember<Element> element_;
 
-  State state_ = kUnlocked;
+  StateChangeHelper state_;
   LayoutRect pending_frame_rect_;
   base::Optional<LayoutRect> locked_frame_rect_;
 
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index d553821..40d26070 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -132,6 +132,8 @@
   ASSERT_TRUE(text_finder.Find(identifier, search_text, *find_options,
                                wrap_within_frame));
   text_finder.ClearActiveFindMatch();
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
 
   auto* element = GetDocument().getElementById("container");
   {
@@ -145,6 +147,8 @@
   EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle());
   EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout());
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1);
 
   UpdateAllLifecyclePhasesForTest();
 
@@ -152,6 +156,8 @@
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldStyle());
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldLayout());
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1);
 
   EXPECT_FALSE(element->GetDisplayLockContext()->IsSearchable());
 
@@ -171,6 +177,9 @@
 
   UpdateAllLifecyclePhasesForTest();
 
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
+
   EXPECT_TRUE(text_finder.Find(identifier, search_text, *find_options,
                                wrap_within_frame));
 }
@@ -208,6 +217,9 @@
   EXPECT_EQ(1, client.Count());
   client.Reset();
 
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
+
   auto* element = GetDocument().getElementById("container");
   {
     auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
@@ -220,6 +232,8 @@
   EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle());
   EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout());
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1);
 
   UpdateAllLifecyclePhasesForTest();
 
@@ -227,6 +241,8 @@
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldStyle());
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldLayout());
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1);
 
   EXPECT_FALSE(element->GetDisplayLockContext()->IsSearchable());
 
@@ -250,6 +266,9 @@
 
   UpdateAllLifecyclePhasesForTest();
 
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
+
   find_in_page->Find(current_id++, "testing", find_options->Clone());
   EXPECT_FALSE(client.FindResultsAreReady());
   test::RunPendingTasks();
@@ -279,6 +298,8 @@
   ASSERT_TRUE(GetDocument().getElementById("textfield")->IsKeyboardFocusable());
   ASSERT_TRUE(GetDocument().getElementById("textfield")->IsMouseFocusable());
   ASSERT_TRUE(GetDocument().getElementById("textfield")->IsFocusable());
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
 
   auto* element = GetDocument().getElementById("container");
   {
@@ -292,6 +313,8 @@
   EXPECT_TRUE(element->GetDisplayLockContext()->ShouldStyle());
   EXPECT_TRUE(element->GetDisplayLockContext()->ShouldLayout());
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1);
 
   UpdateAllLifecyclePhasesForTest();
 
@@ -299,6 +322,8 @@
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldStyle());
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldLayout());
   EXPECT_FALSE(element->GetDisplayLockContext()->ShouldPaint());
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1);
 
   // The input should not be focusable now.
   EXPECT_FALSE(
@@ -323,6 +348,8 @@
 
   UpdateAllLifecyclePhasesForTest();
 
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
   EXPECT_TRUE(GetDocument().getElementById("textfield")->IsKeyboardFocusable());
   EXPECT_TRUE(GetDocument().getElementById("textfield")->IsMouseFocusable());
   EXPECT_TRUE(GetDocument().getElementById("textfield")->IsFocusable());
@@ -332,4 +359,95 @@
   EXPECT_EQ(GetDocument().FocusedElement(),
             GetDocument().getElementById("textfield"));
 }
+
+TEST_F(DisplayLockContextTest, LockedCountsWithMultipleLocks) {
+  ResizeAndFocus();
+  SetHtmlInnerHTML(R"HTML(
+    <style>
+    .container {
+      width: 100px;
+      height: 100px;
+      contain: content;
+    }
+    </style>
+    <body>
+    <div id="one" class="container">
+      <div id="two" class="container"></div>
+    </div>
+    <div id="three" class="container"></div>
+    </body>
+  )HTML");
+
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
+
+  auto* one = GetDocument().getElementById("one");
+  auto* two = GetDocument().getElementById("two");
+  auto* three = GetDocument().getElementById("three");
+
+  auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
+  {
+    ScriptState::Scope scope(script_state);
+    one->getDisplayLockForBindings()->acquire(script_state, nullptr);
+  }
+
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1);
+
+  {
+    ScriptState::Scope scope(script_state);
+    two->getDisplayLockForBindings()->acquire(script_state, nullptr);
+  }
+
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 2);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 2);
+
+  {
+    ScriptState::Scope scope(script_state);
+    three->getDisplayLockForBindings()->acquire(script_state, nullptr);
+  }
+
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 3);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 3);
+
+  UpdateAllLifecyclePhasesForTest();
+
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 3);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 3);
+
+  // Now commit the inner lock.
+  {
+    ScriptState::Scope scope(script_state);
+    two->getDisplayLockForBindings()->commit(script_state);
+  }
+
+  UpdateAllLifecyclePhasesForTest();
+
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 2);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 2);
+
+  // Commit the outer lock.
+  {
+    ScriptState::Scope scope(script_state);
+    one->getDisplayLockForBindings()->commit(script_state);
+  }
+
+  UpdateAllLifecyclePhasesForTest();
+
+  // Both inner and outer locks should have committed.
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 1);
+
+  // Commit the sibling lock.
+  {
+    ScriptState::Scope scope(script_state);
+    three->getDisplayLockForBindings()->commit(script_state);
+  }
+
+  UpdateAllLifecyclePhasesForTest();
+
+  // Both inner and outer locks should have committed.
+  EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0);
+  EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
+}
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index e157188f..62a0b124 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2625,7 +2625,8 @@
   // subtree. We need to figure out if there is a supplementary structure that
   // we can use to quickly identify nodes that are in the locked subtree.
   Vector<DisplayLockContext::ScopedForcedUpdate> scoped_update_forced_list;
-  if (RuntimeEnabledFeatures::DisplayLockingEnabled()) {
+  if (RuntimeEnabledFeatures::DisplayLockingEnabled() &&
+      LockedDisplayLockCount() > 0) {
     for (auto* ancestor = node; ancestor;
          ancestor = ancestor->ParentOrShadowHostNode()) {
       if (!ancestor->IsElementNode())
@@ -7854,6 +7855,32 @@
   num_canvases_++;
 }
 
+void Document::AddActivationBlockingDisplayLock() {
+  ++activation_blocking_display_lock_count_;
+}
+
+void Document::RemoveActivationBlockingDisplayLock() {
+  DCHECK_GT(activation_blocking_display_lock_count_, 0);
+  --activation_blocking_display_lock_count_;
+}
+
+int Document::ActivationBlockingDisplayLockCount() const {
+  return activation_blocking_display_lock_count_;
+}
+
+void Document::AddLockedDisplayLock() {
+  ++locked_display_lock_count_;
+}
+
+void Document::RemoveLockedDisplayLock() {
+  DCHECK_GT(locked_display_lock_count_, 0);
+  --locked_display_lock_count_;
+}
+
+int Document::LockedDisplayLockCount() const {
+  return locked_display_lock_count_;
+}
+
 void Document::ExecuteJavaScriptUrl(
     const KURL& url,
     ContentSecurityPolicyDisposition disposition) {
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index f71aae0..b4d0984 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1515,6 +1515,15 @@
   void ProcessJavaScriptUrl(const KURL&, ContentSecurityPolicyDisposition);
   void CancelPendingJavaScriptUrl();
 
+  // Functions to keep count of display locks in this document.
+  void AddActivationBlockingDisplayLock();
+  void RemoveActivationBlockingDisplayLock();
+  int ActivationBlockingDisplayLockCount() const;
+
+  void AddLockedDisplayLock();
+  void RemoveLockedDisplayLock();
+  int LockedDisplayLockCount() const;
+
  protected:
   void DidUpdateSecurityOrigin() final;
 
@@ -1951,6 +1960,11 @@
   // The number of canvas elements on the document
   int num_canvases_ = 0;
 
+  // Number of activation blocking display locks currently in this document.
+  int activation_blocking_display_lock_count_ = 0;
+  // Number of locked display locks in the document.
+  int locked_display_lock_count_ = 0;
+
   // A list of all the navigation_initiator bindings owned by this document.
   // Used to report CSP violations that result from CSP blocking
   // navigation requests that were initiated by this document.
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index ec1290c..81cf0e0 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -223,6 +223,11 @@
                  ConstructionType type)
     : ContainerNode(document, type), tag_name_(tag_name) {}
 
+Element::~Element() {
+  if (auto* context = GetDisplayLockContext())
+    context->ElementWasDestroyed(GetDocument());
+}
+
 inline ElementRareData* Element::GetElementRareData() const {
   DCHECK(HasRareData());
   return static_cast<ElementRareData*>(RareData());
@@ -3356,6 +3361,10 @@
 bool Element::DisplayLockPreventsActivation() const {
   if (!RuntimeEnabledFeatures::DisplayLockingEnabled())
     return false;
+
+  if (GetDocument().ActivationBlockingDisplayLockCount() == 0)
+    return false;
+
   // TODO(vmpstr): Similar to Document::EnsurePaintLocationDataValidForNode(),
   // this iterates up to the ancestor hierarchy looking for locked display
   // locks. This is inefficient, particularly since it's unlikely that this will
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 7f0cd85..133d569 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -161,6 +161,7 @@
   static Element* Create(const QualifiedName&, Document*);
 
   Element(const QualifiedName& tag_name, Document*, ConstructionType);
+  ~Element() override;
 
   DEFINE_ATTRIBUTE_EVENT_LISTENER(beforecopy, kBeforecopy);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(beforecut, kBeforecut);
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index cf51c26..e8c4fe4 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1473,7 +1473,7 @@
     ResizeViewWhileAnchored(top_controls_height, bottom_controls_height,
                             browser_controls_shrink_layout);
   }
-  SendResizeEventAndRepaint();
+  SendResizeEventForMainFrame();
 }
 
 void WebViewImpl::Resize(const WebSize& new_size) {
@@ -2506,7 +2506,10 @@
   }
   SetPageScaleFactor(new_page_scale_factor);
 
-  UpdateLayerTreeViewport();
+  // The constraints may have changed above which affects the page scale limits,
+  // so we must update those even though SetPageScaleFactor() may do the same if
+  // the scale factor is changed.
+  UpdateLayerTreeViewPageScale();
 }
 
 void WebViewImpl::UpdatePageDefinedViewportConstraints(
@@ -2762,7 +2765,7 @@
   return HitTestResultForRootFramePos(point_in_root_frame);
 }
 
-void WebViewImpl::SendResizeEventAndRepaint() {
+void WebViewImpl::SendResizeEventForMainFrame() {
   // FIXME: This is wrong. The LocalFrameView is responsible sending a
   // resizeEvent as part of layout. Layout is also responsible for sending
   // invalidations to the embedder. This method and all callers may be wrong. --
@@ -2772,14 +2775,8 @@
     MainFrameImpl()->GetFrame()->GetDocument()->EnqueueResizeEvent();
   }
 
-  if (AsWidget().client) {
-    if (layer_tree_view_) {
-      UpdateLayerTreeViewport();
-    } else {
-      WebRect damaged_rect(0, 0, size_.width, size_.height);
-      AsWidget().client->DidInvalidateRect(damaged_rect);
-    }
-  }
+  // A resized main frame can change the page scale limits.
+  UpdateLayerTreeViewPageScale();
 }
 
 void WebViewImpl::ConfigureAutoResizeMode() {
@@ -2993,6 +2990,7 @@
 
 void WebViewImpl::ResizeAfterLayout() {
   DCHECK(MainFrameImpl());
+
   if (!AsView().client || !AsView().client->CanUpdateLayout())
     return;
 
@@ -3007,7 +3005,7 @@
       view->SetInitialViewportSize(size_);
 
       AsView().client->DidAutoResize(size_);
-      SendResizeEventAndRepaint();
+      SendResizeEventForMainFrame();
     }
   }
 
@@ -3044,7 +3042,7 @@
 
 void WebViewImpl::PageScaleFactorChanged() {
   GetPageScaleConstraintsSet().SetNeedsReset(false);
-  UpdateLayerTreeViewport();
+  UpdateLayerTreeViewPageScale();
   AsView().client->PageScaleFactorChanged();
   dev_tools_emulator_->MainFrameScrollOrScaleChanged();
 }
@@ -3231,12 +3229,9 @@
 }
 
 void WebViewImpl::InvalidateRect(const IntRect& rect) {
-  if (layer_tree_view_) {
-    UpdateLayerTreeViewport();
-  } else if (AsWidget().client) {
-    // This is only for WebViewPlugin.
+  // This is only for WebViewPlugin.
+  if (!does_composite_ && AsWidget().client)
     AsWidget().client->DidInvalidateRect(rect);
-  }
 }
 
 PaintLayerCompositor* WebViewImpl::Compositor() const {
@@ -3268,6 +3263,10 @@
   // WebViewImpl, so don't allow cc to commit any frames Blink might
   // try to create in the meantime.
   scoped_defer_main_frame_update_ = layer_tree_view_->DeferMainFrameUpdate();
+
+  // Any changes to the Page while a main frame was remote need to be propagated
+  // to the widget/compositor for the main frame when it becomes local.
+  UpdateLayerTreeViewPageScale();
 }
 
 void WebViewImpl::ApplyViewportChanges(const ApplyViewportChangesArgs& args) {
@@ -3362,9 +3361,12 @@
     target_node->GetDocument().EnqueueScrollEndEventForNode(target_node);
 }
 
-void WebViewImpl::UpdateLayerTreeViewport() {
-  if (!GetPage() || !layer_tree_view_)
+void WebViewImpl::UpdateLayerTreeViewPageScale() {
+  // Non-composited WebViews can not use page scale factor.
+  if (!does_composite_)
     return;
+  // TODO(danakj): When the main frame is remote the LayerTreeView is not
+  // present. So add early-return here.
 
   layer_tree_view_->SetPageScaleFactorAndLimits(
       PageScaleFactor(), MinimumPageScaleFactor(), MaximumPageScaleFactor());
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index 2ab90e6..dc2442e 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -342,8 +342,9 @@
   void ExitFullscreen(LocalFrame&);
   void FullscreenElementChanged(Element* old_element, Element* new_element);
 
-  // Exposed for the purpose of overriding device metrics.
-  void SendResizeEventAndRepaint();
+  // Sends a request to the main frame's view to resize, and updates the page
+  // scale limits if needed.
+  void SendResizeEventForMainFrame();
 
   // Exposed for testing purposes.
   bool HasHorizontalScrollbar();
@@ -497,7 +498,7 @@
   void SetIsAcceleratedCompositingActive(bool);
   void DoComposite();
   void ReallocateRenderer();
-  void UpdateLayerTreeViewport();
+  void UpdateLayerTreeViewPageScale();
   void UpdateLayerTreeBackgroundColor();
   void UpdateDeviceEmulationTransform();
 
diff --git a/third_party/blink/renderer/core/frame/ad_tracker_test.cc b/third_party/blink/renderer/core/frame/ad_tracker_test.cc
index 56558d4..8983435 100644
--- a/third_party/blink/renderer/core/frame/ad_tracker_test.cc
+++ b/third_party/blink/renderer/core/frame/ad_tracker_test.cc
@@ -271,6 +271,26 @@
   EXPECT_TRUE(ad_tracker_->IsAdScriptInStack());
 }
 
+TEST_F(AdTrackerSimTest, RedirectToAdUrl) {
+  SimSubresourceRequest redirect_script(
+      "https://example.com/redirect_script.js",
+      "https://example.com/ad_script.js", "text/javascript");
+  SimSubresourceRequest ad_script("https://example.com/ad_script.js",
+                                  "text/javascript");
+
+  ad_tracker_->SetAdSuffix("ad_script.js");
+
+  main_resource_->Complete(
+      "<body><script src='redirect_script.js'></script></body>");
+
+  ad_script.Complete("");
+
+  EXPECT_FALSE(ad_tracker_->RequestWithUrlTaggedAsAd(
+      "https://example.com/redirect_script.js"));
+  EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(
+      "https://example.com/ad_script.js"));
+}
+
 TEST_F(AdTrackerSimTest, AdResourceDetectedByContext) {
   SimSubresourceRequest ad_script("https://example.com/ad_script.js",
                                   "text/javascript");
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
index 856dda6..b0ef5f68 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -410,6 +410,9 @@
   // TODO(danakj): Remove this! Make WebViewImpl not need a WebWidgetClient when
   // the main frame is remote.
   web_view_->SetWebWidgetClient(test_web_widget_client_);
+  // TODO(danakj): Make this part of attaching the main frame's WebFrameWidget.
+  web_view_->MainFrameWidget()->SetLayerTreeView(
+      test_web_widget_client_->layer_tree_view());
 
   return web_view_;
 }
@@ -490,7 +493,11 @@
 
 void TestWebFrameClient::FrameDetached(DetachType type) {
   if (frame_->FrameWidget()) {
-    frame_->FrameWidget()->WillCloseLayerTreeView();
+    // TODO(dcheng): This shouldn't exclude the main frame, but it is currently
+    // unsafe to close the LTV for the main frame: that's handled separately by
+    // closing the entire WebView itself.
+    if (frame_->Parent())
+      frame_->FrameWidget()->WillCloseLayerTreeView();
     frame_->FrameWidget()->Close();
   }
 
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.cc b/third_party/blink/renderer/core/input/pointer_event_manager.cc
index 5fe74b6..0d527c2 100644
--- a/third_party/blink/renderer/core/input/pointer_event_manager.cc
+++ b/third_party/blink/renderer/core/input/pointer_event_manager.cc
@@ -702,9 +702,12 @@
         mouse_event.pointer_type)] = true;
   }
 
+  // Only calculate mouse target if either mouse compatibility event or click
+  // should be sent.
   if (pointer_event->isPrimary() &&
-      !prevent_mouse_event_for_pointer_type_[ToPointerTypeIndex(
-          mouse_event.pointer_type)]) {
+      (!prevent_mouse_event_for_pointer_type_[ToPointerTypeIndex(
+           mouse_event.pointer_type)] ||
+       (!skip_click_dispatch && event_type == WebInputEvent::kPointerUp))) {
     Element* mouse_target = effective_target;
     // Event path could be null if the pointer event is not dispatched.
     if (!event_handling_util::IsInDocument(mouse_target) &&
@@ -718,11 +721,14 @@
         }
       }
     }
-    result = event_handling_util::MergeEventResult(
-        result,
-        mouse_event_manager_->DispatchMouseEvent(
-            mouse_target, MouseEventNameForPointerEventInputType(event_type),
-            mouse_event, canvas_region_id, &last_mouse_position, nullptr));
+    if (!prevent_mouse_event_for_pointer_type_[ToPointerTypeIndex(
+            mouse_event.pointer_type)]) {
+      result = event_handling_util::MergeEventResult(
+          result,
+          mouse_event_manager_->DispatchMouseEvent(
+              mouse_target, MouseEventNameForPointerEventInputType(event_type),
+              mouse_event, canvas_region_id, &last_mouse_position, nullptr));
+    }
     if (!skip_click_dispatch && mouse_target &&
         event_type == WebInputEvent::kPointerUp) {
       mouse_event_manager_->DispatchMouseClickIfNeeded(
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index 6c5b8516..13a1990f 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -2560,14 +2560,9 @@
   return false;
 }
 
-void LayoutBlockFlow::SetPaintFragment(const NGBlockBreakToken*,
-                                       scoped_refptr<const NGPhysicalFragment>,
-                                       NGPhysicalOffset) {}
-
-void LayoutBlockFlow::UpdatePaintFragmentFromCachedLayoutResult(
+void LayoutBlockFlow::SetPaintFragment(
     const NGBlockBreakToken*,
-    scoped_refptr<const NGPhysicalFragment>,
-    NGPhysicalOffset) {}
+    scoped_refptr<const NGPhysicalFragment>) {}
 
 void LayoutBlockFlow::ComputeVisualOverflow(
     bool recompute_floats) {
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h
index 14a179e2..90c5999 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -67,7 +67,6 @@
 class NGPhysicalFragment;
 
 struct NGInlineNodeData;
-struct NGPhysicalOffset;
 
 enum IndentTextOrNot { kDoNotIndentText, kIndentText };
 
@@ -470,12 +469,7 @@
   virtual bool AreCachedLinesValidFor(const NGConstraintSpace&) const;
   virtual void WillCollectInlines() {}
   virtual void SetPaintFragment(const NGBlockBreakToken*,
-                                scoped_refptr<const NGPhysicalFragment>,
-                                NGPhysicalOffset);
-  virtual void UpdatePaintFragmentFromCachedLayoutResult(
-      const NGBlockBreakToken*,
-      scoped_refptr<const NGPhysicalFragment>,
-      NGPhysicalOffset);
+                                scoped_refptr<const NGPhysicalFragment>);
   virtual const NGPhysicalBoxFragment* CurrentFragment() const {
     return nullptr;
   }
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
index a60e9b1b..2131ce9 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
@@ -52,33 +52,6 @@
   for (const NGOutOfFlowPositionedDescendant& descendant :
        result->OutOfFlowPositionedDescendants())
     descendant.node.UseOldOutOfFlowPositioning();
-
-  const NGPhysicalBoxFragment* fragment =
-      ToNGPhysicalBoxFragment(result->PhysicalFragment());
-
-  // This object has already been positioned in legacy layout by our containing
-  // block. Copy the position and place the fragment.
-  //
-  // TODO(kojii): This object is not positioned yet when the containing legacy
-  // layout is not normal flow; e.g., table or flexbox. They lay out children to
-  // determine the overall layout, then move children. In flexbox case,
-  // LayoutLineItems() lays out children, which calls this function. Then later,
-  // ApplyLineItemPosition() changes Location() of the children. See also
-  // NGPhysicalFragment::IsPlacedByLayoutNG(). crbug.com/788590
-  //
-  // TODO(crbug.com/781241): LogicalLeft() is not calculated by the
-  // containing block until after our layout.
-  const LayoutBlock* containing_block = ContainingBlock();
-  NGPhysicalOffset physical_offset;
-  if (containing_block) {
-    NGPhysicalSize containing_block_size(containing_block->Size().Width(),
-                                         containing_block->Size().Height());
-    NGLogicalOffset logical_offset(LogicalLeft(), LogicalTop());
-    physical_offset = logical_offset.ConvertToPhysical(
-        constraint_space.GetWritingMode(), constraint_space.Direction(),
-        containing_block_size, fragment->Size());
-  }
-  result->SetOffset(physical_offset);
 }
 
 void LayoutNGBlockFlow::UpdateOutOfFlowBlockLayout() {
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc
index da796ec..2be3541 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc
@@ -31,22 +31,6 @@
   for (NGOutOfFlowPositionedDescendant descendant :
        result->OutOfFlowPositionedDescendants())
     descendant.node.UseOldOutOfFlowPositioning();
-
-  const NGPhysicalBoxFragment* fragment =
-      ToNGPhysicalBoxFragment(result->PhysicalFragment());
-
-  // Pasted from layout_ng_block_flow. TODO(dgrogan): Factor a utility method.
-  const LayoutBlock* containing_block = ContainingBlock();
-  NGPhysicalOffset physical_offset;
-  if (containing_block) {
-    NGPhysicalSize containing_block_size(containing_block->Size().Width(),
-                                         containing_block->Size().Height());
-    NGLogicalOffset logical_offset(LogicalLeft(), LogicalTop());
-    physical_offset = logical_offset.ConvertToPhysical(
-        constraint_space.GetWritingMode(), constraint_space.Direction(),
-        containing_block_size, fragment->Size());
-  }
-  result->SetOffset(physical_offset);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 9a70c3d..07a20de2 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -397,8 +397,7 @@
 template <typename Base>
 void LayoutNGMixin<Base>::SetPaintFragment(
     const NGBlockBreakToken* break_token,
-    scoped_refptr<const NGPhysicalFragment> fragment,
-    NGPhysicalOffset offset) {
+    scoped_refptr<const NGPhysicalFragment> fragment) {
   DCHECK(!break_token || break_token->InputNode().GetLayoutBox() == this);
 
   scoped_refptr<NGPaintFragment>* current =
@@ -406,7 +405,7 @@
   DCHECK(current);
   bool has_old = current->get();
   if (fragment) {
-    *current = NGPaintFragment::Create(std::move(fragment), offset, break_token,
+    *current = NGPaintFragment::Create(std::move(fragment), break_token,
                                        std::move(*current));
   } else {
     *current = nullptr;
@@ -419,23 +418,6 @@
 }
 
 template <typename Base>
-void LayoutNGMixin<Base>::UpdatePaintFragmentFromCachedLayoutResult(
-    const NGBlockBreakToken* break_token,
-    scoped_refptr<const NGPhysicalFragment> fragment,
-    NGPhysicalOffset fragment_offset) {
-  DCHECK(fragment);
-  DCHECK(fragment->GetLayoutObject() == this);
-  DCHECK(!break_token || break_token->InputNode().GetLayoutBox() == this);
-
-  scoped_refptr<NGPaintFragment>* current =
-      NGPaintFragment::Find(&paint_fragment_, break_token);
-  DCHECK(current);
-  DCHECK(*current);
-  (*current)->UpdateFromCachedLayoutResult(std::move(fragment),
-                                           fragment_offset);
-}
-
-template <typename Base>
 void LayoutNGMixin<Base>::InvalidateDisplayItemClients(
     PaintInvalidationReason invalidation_reason) const {
   if (NGPaintFragment* fragment = PaintFragment()) {
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
index 8dd8445..e1898a69 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -23,7 +23,6 @@
 class NGPaintFragment;
 class NGPhysicalFragment;
 struct NGInlineNodeData;
-struct NGPhysicalOffset;
 
 // This mixin holds code shared between LayoutNG subclasses of
 // LayoutBlockFlow.
@@ -76,12 +75,7 @@
 
   NGPaintFragment* PaintFragment() const final { return paint_fragment_.get(); }
   void SetPaintFragment(const NGBlockBreakToken*,
-                        scoped_refptr<const NGPhysicalFragment>,
-                        NGPhysicalOffset) final;
-  void UpdatePaintFragmentFromCachedLayoutResult(
-      const NGBlockBreakToken*,
-      scoped_refptr<const NGPhysicalFragment>,
-      NGPhysicalOffset) final;
+                        scoped_refptr<const NGPhysicalFragment>) final;
 
  protected:
   bool IsOfType(LayoutObject::LayoutObjectType) const override;
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc
index 7db04f9..47d601b 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc
@@ -31,22 +31,6 @@
   for (NGOutOfFlowPositionedDescendant descendant :
        result->OutOfFlowPositionedDescendants())
     descendant.node.UseOldOutOfFlowPositioning();
-
-  const NGPhysicalBoxFragment* fragment =
-      ToNGPhysicalBoxFragment(result->PhysicalFragment());
-
-  const LayoutBox* section = LocationContainer();
-  NGPhysicalOffset physical_offset;
-  if (section) {
-    NGPhysicalSize section_size(section->Size().Width(),
-                                section->Size().Height());
-    NGLogicalOffset logical_offset(LogicalLeft() + section->Location().X(),
-                                   LogicalTop() + section->Location().Y());
-    physical_offset = logical_offset.ConvertToPhysical(
-        constraint_space.GetWritingMode(), constraint_space.Direction(),
-        section_size, fragment->Size());
-  }
-  result->SetOffset(physical_offset);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 0d0c84b..4772228 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -241,12 +241,6 @@
       // don't re-set the result here.
       block_flow->SetCachedLayoutResult(constraint_space, break_token,
                                         *layout_result);
-      if (!constraint_space.IsIntermediateLayout() && first_child &&
-          first_child.IsInline()) {
-        block_flow->UpdatePaintFragmentFromCachedLayoutResult(
-            ToNGBlockBreakToken(break_token), layout_result->PhysicalFragment(),
-            layout_result->Offset());
-      }
       return layout_result;
     }
   }
@@ -351,13 +345,11 @@
       }
 
       block_flow->SetPaintFragment(ToNGBlockBreakToken(break_token),
-                                   layout_result->PhysicalFragment(),
-                                   layout_result->Offset());
+                                   layout_result->PhysicalFragment());
     } else {
       // We still need to clear paint fragments in case it had inline children,
       // and thus had NGPaintFragment.
-      block_flow->SetPaintFragment(ToNGBlockBreakToken(break_token), nullptr,
-                                   NGPhysicalOffset());
+      block_flow->SetPaintFragment(ToNGBlockBreakToken(break_token), nullptr);
     }
   }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
index 2bd55f1..1db63aa 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
@@ -24,7 +24,7 @@
   final_break_after_ = builder->previous_break_after_;
   has_forced_break_ = builder->has_forced_break_;
   DCHECK(physical_fragment) << "Use the other constructor for aborting layout";
-  root_fragment_.fragment_ = std::move(physical_fragment);
+  physical_fragment_ = std::move(physical_fragment);
   oof_positioned_descendants_ = std::move(builder->oof_positioned_descendants_);
 }
 
@@ -32,7 +32,7 @@
     scoped_refptr<const NGPhysicalFragment> physical_fragment,
     NGLineBoxFragmentBuilder* builder)
     : NGLayoutResult(builder) {
-  root_fragment_.fragment_ = std::move(physical_fragment);
+  physical_fragment_ = std::move(physical_fragment);
   oof_positioned_descendants_ = std::move(builder->oof_positioned_descendants_);
 }
 
@@ -49,7 +49,7 @@
 // We can't use =default here because RefCounted can't be copied.
 NGLayoutResult::NGLayoutResult(const NGLayoutResult& other,
                                base::Optional<LayoutUnit> bfc_block_offset)
-    : root_fragment_(other.root_fragment_),
+    : physical_fragment_(other.physical_fragment_),
       oof_positioned_descendants_(other.oof_positioned_descendants_),
       unpositioned_list_marker_(other.unpositioned_list_marker_),
       exclusion_space_(other.exclusion_space_),
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
index 27b5f6a..3f8fd4e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
@@ -48,10 +48,8 @@
   ~NGLayoutResult();
 
   const NGPhysicalFragment* PhysicalFragment() const {
-    return root_fragment_.get();
+    return physical_fragment_.get();
   }
-  NGPhysicalOffset Offset() const { return root_fragment_.Offset(); }
-  void SetOffset(NGPhysicalOffset offset) { root_fragment_.offset_ = offset; }
 
   const Vector<NGOutOfFlowPositionedDescendant>&
   OutOfFlowPositionedDescendants() const {
@@ -76,8 +74,8 @@
   const NGMarginStrut EndMarginStrut() const { return end_margin_strut_; }
 
   const LayoutUnit IntrinsicBlockSize() const {
-    DCHECK(root_fragment_->Type() == NGPhysicalFragment::kFragmentBox ||
-           root_fragment_->Type() ==
+    DCHECK(physical_fragment_->Type() == NGPhysicalFragment::kFragmentBox ||
+           physical_fragment_->Type() ==
                NGPhysicalFragment::kFragmentRenderedLegend);
     return intrinsic_block_size_;
   }
@@ -139,7 +137,7 @@
 
   static bool DependsOnPercentageBlockSize(const NGContainerFragmentBuilder&);
 
-  NGLink root_fragment_;
+  scoped_refptr<const NGPhysicalFragment> physical_fragment_;
   Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
 
   NGUnpositionedListMarker unpositioned_list_marker_;
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 7fcfd76af..8eb50a3 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -125,7 +125,10 @@
   if (address_space)
     request.SetExternalRequestStateFromRequestorAddressSpace(*address_space);
 
-  if (blink::RuntimeEnabledFeatures::SecMetadataEnabled()) {
+  scoped_refptr<SecurityOrigin> url_origin =
+      SecurityOrigin::Create(request.Url());
+  if (blink::RuntimeEnabledFeatures::SecMetadataEnabled() &&
+      url_origin->IsPotentiallyTrustworthy()) {
     const char* destination_value =
         GetDestinationFromContext(request.GetRequestContext());
 
@@ -138,9 +141,8 @@
     if (strncmp(destination_value, "document", 8) != 0 &&
         request.GetRequestContext() != mojom::RequestContextType::INTERNAL) {
       const char* site_value = "cross-site";
-      if (SecurityOrigin::Create(request.Url())
-              ->IsSameSchemeHostPort(
-                  fetch_client_settings_object.GetSecurityOrigin())) {
+      if (url_origin->IsSameSchemeHostPort(
+              fetch_client_settings_object.GetSecurityOrigin())) {
         site_value = "same-origin";
       } else {
         OriginAccessEntry access_entry(
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index 8df4a757..3fa2735 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -317,7 +317,8 @@
     return;
   CompositorFilterOperations backdrop_filters =
       OwningLayer().CreateCompositorFilterOperationsForBackdropFilter();
-  gfx::RectF filter_bounds = OwningLayer().BackdropFilterBounds();
+  gfx::RRectF filter_bounds = OwningLayer().BackdropFilterBounds(
+      OwningLayer().BackdropFilterReferenceBox());
   graphics_layer_->SetBackdropFilters(backdrop_filters, filter_bounds);
 }
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index 2337ad0..242d4a66 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -288,7 +288,6 @@
 
 scoped_refptr<NGPaintFragment> NGPaintFragment::Create(
     scoped_refptr<const NGPhysicalFragment> fragment,
-    NGPhysicalOffset offset,
     const NGBlockBreakToken* block_break_token,
     scoped_refptr<NGPaintFragment> previous_instance) {
   DCHECK(fragment);
@@ -296,7 +295,7 @@
   bool populate_children = fragment->IsContainer();
   bool has_previous_instance = previous_instance.get();
   scoped_refptr<NGPaintFragment> paint_fragment =
-      CreateOrReuse(std::move(fragment), offset, nullptr,
+      CreateOrReuse(std::move(fragment), NGPhysicalOffset(), nullptr,
                     std::move(previous_instance), &populate_children);
 
   if (populate_children) {
@@ -317,33 +316,6 @@
   return *rare_data_;
 }
 
-void NGPaintFragment::UpdateFromCachedLayoutResult(
-    scoped_refptr<const NGPhysicalFragment> fragment,
-    NGPhysicalOffset offset) {
-  // TODO(crbug.com/924449): Once we get the caller passes null physical
-  // fragment, we'll change to DCHECK().
-  CHECK(fragment);
-
-#if DCHECK_IS_ON()
-  // When updating to a cached layout result, only offset can change. Check
-  // children do not change.
-  const NGPhysicalContainerFragment& container_fragment =
-      ToNGPhysicalContainerFragment(*fragment);
-  NGPaintFragment* child = FirstChild();
-  for (unsigned i = 0; i < container_fragment.Children().size();
-       i++, child = child->NextSibling()) {
-    DCHECK(child);
-    DCHECK_EQ(child->physical_fragment_.get(),
-              container_fragment.Children()[i].get());
-  }
-  DCHECK(!child);
-#endif
-
-  DCHECK_EQ(physical_fragment_.get(), fragment.get());
-  physical_fragment_ = std::move(fragment);
-  offset_ = offset;
-}
-
 const NGPaintFragment* NGPaintFragment::Next() const {
   if (!rare_data_)
     return nullptr;
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
index e20417d..47f11ca 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -47,7 +47,6 @@
 
   static scoped_refptr<NGPaintFragment> Create(
       scoped_refptr<const NGPhysicalFragment>,
-      NGPhysicalOffset offset,
       const NGBlockBreakToken* break_token,
       scoped_refptr<NGPaintFragment> previous_instance = nullptr);
 
@@ -55,10 +54,6 @@
     return *physical_fragment_;
   }
 
-  void UpdateFromCachedLayoutResult(
-      scoped_refptr<const NGPhysicalFragment> fragment,
-      NGPhysicalOffset offset);
-
   // Next/last fragment for  when this is fragmented.
   const NGPaintFragment* Next() const;
   void SetNext(scoped_refptr<NGPaintFragment>);
@@ -207,7 +202,10 @@
     return PhysicalFragment().GetLayoutObject();
   }
   const ComputedStyle& Style() const { return PhysicalFragment().Style(); }
-  NGPhysicalOffset Offset() const { return offset_; }
+  NGPhysicalOffset Offset() const {
+    DCHECK(parent_);
+    return offset_;
+  }
   NGPhysicalSize Size() const { return PhysicalFragment().Size(); }
 
   // Converts the given point, relative to the fragment itself, into a position
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index af8ef25..86e1c34 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -2469,7 +2469,7 @@
   return FloatRect();
 }
 
-FloatRect PaintLayer::BackdropFilterBounds() const {
+FloatRect PaintLayer::BackdropFilterReferenceBox() const {
   FloatRect reference_box(GetLayoutObject().BorderBoundingBox());
   float zoom = GetLayoutObject().StyleRef().EffectiveZoom();
   if (zoom != 1)
@@ -2478,6 +2478,16 @@
   return reference_box;
 }
 
+gfx::RRectF PaintLayer::BackdropFilterBounds(
+    const FloatRect& reference_box) const {
+  auto& style = GetLayoutObject().StyleRef();
+  if (!style.HasBorderRadius())
+    return gfx::RRectF(reference_box, 0);
+  FloatRoundedRect rrect = style.GetRoundedBorderFor(LayoutRect(reference_box));
+  // FloatRoundedRect has a typecast to SkRRect().
+  return gfx::RRectF(rrect);
+}
+
 bool PaintLayer::HitTestClippedOutByClipPath(
     PaintLayer* root_layer,
     const HitTestLocation& hit_test_location) const {
@@ -3249,15 +3259,15 @@
 
 void PaintLayer::UpdateCompositorFilterOperationsForBackdropFilter(
     CompositorFilterOperations& operations,
-    gfx::RectF* backdrop_filter_bounds) const {
+    gfx::RRectF* backdrop_filter_bounds) const {
   DCHECK(backdrop_filter_bounds);
   const auto& style = GetLayoutObject().StyleRef();
   if (style.BackdropFilter().IsEmpty()) {
     operations.Clear();
     return;
   }
-  FloatRect reference_box = BackdropFilterBounds();
-  *backdrop_filter_bounds = reference_box;
+  FloatRect reference_box = BackdropFilterReferenceBox();
+  *backdrop_filter_bounds = BackdropFilterBounds(reference_box);
   if (operations.IsEmpty() || reference_box != operations.ReferenceBox())
     operations = CreateCompositorFilterOperationsForBackdropFilter();
 }
@@ -3270,7 +3280,7 @@
     return return_value;
   }
   float zoom = style.EffectiveZoom();
-  FloatRect reference_box = BackdropFilterBounds();
+  FloatRect reference_box = BackdropFilterReferenceBox();
   return_value = FilterEffectBuilder(reference_box, zoom)
                      .BuildFilterOperations(style.BackdropFilter());
   DCHECK(!return_value.IsEmpty());
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h
index 920dea1..0e82d5a 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -618,7 +618,7 @@
   // EffectPaintPropertyNode.
   void UpdateCompositorFilterOperationsForBackdropFilter(
       CompositorFilterOperations& operations,
-      gfx::RectF* backdrop_filter_bounds) const;
+      gfx::RRectF* backdrop_filter_bounds) const;
   CompositorFilterOperations CreateCompositorFilterOperationsForBackdropFilter()
       const;
 
@@ -648,7 +648,8 @@
   // coordinate system of the object with the filter. Filter bounds is the
   // reference box, offset by the object's location in the graphics layer.
   FloatRect FilterReferenceBox() const;
-  FloatRect BackdropFilterBounds() const;
+  FloatRect BackdropFilterReferenceBox() const;
+  gfx::RRectF BackdropFilterBounds(const FloatRect& reference_box) const;
 
   void UpdateFilterReferenceBox();
   void UpdateFilters(const ComputedStyle* old_style,
diff --git a/third_party/blink/renderer/core/testing/sim/sim_network.cc b/third_party/blink/renderer/core/testing/sim/sim_network.cc
index 69d726a6..e76da21 100644
--- a/third_party/blink/renderer/core/testing/sim/sim_network.cc
+++ b/third_party/blink/renderer/core/testing/sim/sim_network.cc
@@ -95,7 +95,14 @@
   requests_.insert(request.url_.GetString(), &request);
   WebURLResponse response(request.url_);
   response.SetMIMEType(request.mime_type_);
-  response.SetHTTPStatusCode(200);
+
+  if (request.redirect_url_.IsEmpty()) {
+    response.SetHTTPStatusCode(200);
+  } else {
+    response.SetHTTPStatusCode(302);
+    response.AddHTTPHeaderField("Location", request.redirect_url_);
+  }
+
   Platform::Current()->GetURLLoaderMockFactory()->RegisterURL(request.url_,
                                                               response, "");
 }
diff --git a/third_party/blink/renderer/core/testing/sim/sim_request.cc b/third_party/blink/renderer/core/testing/sim/sim_request.cc
index 4cee44e..f621760 100644
--- a/third_party/blink/renderer/core/testing/sim/sim_request.cc
+++ b/third_party/blink/renderer/core/testing/sim/sim_request.cc
@@ -13,9 +13,11 @@
 namespace blink {
 
 SimRequestBase::SimRequestBase(String url,
+                               String redirect_url,
                                String mime_type,
                                bool start_immediately)
     : url_(url),
+      redirect_url_(redirect_url),
       mime_type_(mime_type),
       start_immediately_(start_immediately),
       started_(false),
@@ -54,6 +56,7 @@
 
 void SimRequestBase::StartInternal() {
   DCHECK(!started_);
+  DCHECK(redirect_url_.IsEmpty());  // client_ is nullptr on redirects
   started_ = true;
   client_->DidReceiveResponse(response_);
 }
@@ -136,12 +139,20 @@
 }
 
 SimRequest::SimRequest(String url, String mime_type)
-    : SimRequestBase(url, mime_type, true /* start_immediately */) {}
+    : SimRequestBase(url, "", mime_type, true /* start_immediately */) {}
 
 SimRequest::~SimRequest() = default;
 
 SimSubresourceRequest::SimSubresourceRequest(String url, String mime_type)
-    : SimRequestBase(url, mime_type, false /* start_immediately */) {}
+    : SimRequestBase(url, "", mime_type, false /* start_immediately */) {}
+
+SimSubresourceRequest::SimSubresourceRequest(String url,
+                                             String redirect_url,
+                                             String mime_type)
+    : SimRequestBase(url,
+                     redirect_url,
+                     mime_type,
+                     false /* start_immediately */) {}
 
 SimSubresourceRequest::~SimSubresourceRequest() = default;
 
diff --git a/third_party/blink/renderer/core/testing/sim/sim_request.h b/third_party/blink/renderer/core/testing/sim/sim_request.h
index 5e897480..c6feb9c 100644
--- a/third_party/blink/renderer/core/testing/sim/sim_request.h
+++ b/third_party/blink/renderer/core/testing/sim/sim_request.h
@@ -36,7 +36,10 @@
   void Complete(const Vector<char>& data);
 
  protected:
-  SimRequestBase(String url, String mime_type, bool start_immediately);
+  SimRequestBase(String url,
+                 String redirect_url,
+                 String mime_type,
+                 bool start_immediately);
   ~SimRequestBase();
 
   void StartInternal();
@@ -53,6 +56,7 @@
   void UsedForNavigation(StaticDataNavigationBodyLoader*);
 
   KURL url_;
+  String redirect_url_;
   String mime_type_;
   bool start_immediately_;
   bool started_;
@@ -78,6 +82,11 @@
 class SimSubresourceRequest final : public SimRequestBase {
  public:
   SimSubresourceRequest(String url, String mime_type);
+
+  // Creates a request that redirects to |redirect_url|. Don't call Start() or
+  // Complete() on these requests.
+  SimSubresourceRequest(String url, String redirect_url, String mime_type);
+
   ~SimSubresourceRequest();
 
   // Starts the response from the server, this is as if the headers and 200 OK
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelineUIUtils.js
index 5334c9e..3993199 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/TimelineUIUtils.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelineUIUtils.js
@@ -109,6 +109,16 @@
         new Timeline.TimelineRecordStyle(Common.UIString('Evaluate Module'), categories['scripting']);
     eventStyles[recordTypes.ParseScriptOnBackground] =
         new Timeline.TimelineRecordStyle(Common.UIString('Parse Script'), categories['scripting']);
+    eventStyles[recordTypes.WasmStreamFromResponseCallback] =
+        new Timeline.TimelineRecordStyle(Common.UIString(ls`Streaming Wasm Response`), categories['scripting']);
+    eventStyles[recordTypes.WasmCompiledModule] =
+        new Timeline.TimelineRecordStyle(Common.UIString(ls`Compiled Wasm Module`), categories['scripting']);
+    eventStyles[recordTypes.WasmCachedModule] =
+        new Timeline.TimelineRecordStyle(Common.UIString(ls`Cached Wasm Module`), categories['scripting']);
+    eventStyles[recordTypes.WasmModuleCacheHit] =
+        new Timeline.TimelineRecordStyle(Common.UIString(ls`Wasm Module Cache Hit`), categories['scripting']);
+    eventStyles[recordTypes.WasmModuleCacheInvalid] =
+        new Timeline.TimelineRecordStyle(Common.UIString(ls`Wasm Module Cache Invalid`), categories['scripting']);
     eventStyles[recordTypes.FrameStartedLoading] =
         new Timeline.TimelineRecordStyle(ls`Frame Started Loading`, categories['loading'], true);
     eventStyles[recordTypes.MarkLoad] =
@@ -560,6 +570,14 @@
           detailsText = Bindings.displayNameForURL(url) + ':' + (eventData['lineNumber'] + 1);
         break;
       }
+      case recordType.WasmCompiledModule:
+      case recordType.WasmModuleCacheHit: {
+        const url = event.args['url'];
+        if (url)
+          detailsText = Bindings.displayNameForURL(url);
+        break;
+      }
+
       case recordType.ParseScriptOnBackground:
       case recordType.XHRReadyStateChange:
       case recordType.XHRLoad: {
@@ -666,6 +684,11 @@
       case recordType.Animation:
       case recordType.EmbedderCallback:
       case recordType.ParseHTML:
+      case recordType.WasmStreamFromResponseCallback:
+      case recordType.WasmCompiledModule:
+      case recordType.WasmModuleCacheHit:
+      case recordType.WasmCachedModule:
+      case recordType.WasmModuleCacheInvalid:
       case recordType.WebSocketCreate:
       case recordType.WebSocketSendHandshakeRequest:
       case recordType.WebSocketReceiveHandshakeResponse:
@@ -893,6 +916,23 @@
         if (url)
           contentHelper.appendLocationRow(ls`Script`, url, eventData['lineNumber'], eventData['columnNumber']);
         break;
+      case recordTypes.WasmStreamFromResponseCallback:
+      case recordTypes.WasmCompiledModule:
+      case recordTypes.WasmCachedModule:
+      case recordTypes.WasmModuleCacheHit:
+      case recordTypes.WasmModuleCacheInvalid:
+        if (eventData) {
+          url = event.args['url'];
+          if (url)
+            contentHelper.appendTextRow(ls`Url`, url);
+          const producedCachedSize = event.args['producedCachedSize'];
+          if (producedCachedSize)
+            contentHelper.appendTextRow(ls`Produced Cache Size`, producedCachedSize);
+          const consumedCachedSize = event.args['consumedCachedSize'];
+          if (consumedCachedSize)
+            contentHelper.appendTextRow(ls`Consumed Cache Size`, consumedCachedSize);
+        }
+        break;
       case recordTypes.Paint:
         const clip = eventData['clip'];
         contentHelper.appendTextRow(ls`Location`, ls`(${clip[0]}, ${clip[1]})`);
diff --git a/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js b/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js
index 1b0efac..65809eb 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline_model/TimelineModel.js
@@ -1211,6 +1211,11 @@
   EvaluateScript: 'EvaluateScript',
   CompileModule: 'v8.compileModule',
   EvaluateModule: 'v8.evaluateModule',
+  WasmStreamFromResponseCallback: 'v8.wasm.streamFromResponseCallback',
+  WasmCompiledModule: 'v8.wasm.compiledModule',
+  WasmCachedModule: 'v8.wasm.cachedModule',
+  WasmModuleCacheHit: 'v8.wasm.moduleCacheHit',
+  WasmModuleCacheInvalid: 'v8.wasm.moduleCacheInvalid',
 
   FrameStartedLoading: 'FrameStartedLoading',
   CommitLoad: 'CommitLoad',
diff --git a/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc b/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc
index c9c643f..8ab112a 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc
@@ -37,7 +37,7 @@
           e0(), EffectPaintPropertyNode::State{
                     layer_transform_.get(), layer_clip_.get(),
                     kColorFilterLuminanceToAlpha, CompositorFilterOperations(),
-                    0.789f, CompositorFilterOperations(), gfx::RectF(),
+                    0.789f, CompositorFilterOperations(), gfx::RRectF(),
                     SkBlendMode::kSrcIn});
     }
     return PropertyTreeState(layer_transform_.get(), layer_clip_.get(),
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
index 60d859d9..444e2f2a 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
@@ -941,7 +941,7 @@
 
 void GraphicsLayer::SetBackdropFilters(
     CompositorFilterOperations filters,
-    const gfx::RectF& backdrop_filter_bounds) {
+    const gfx::RRectF& backdrop_filter_bounds) {
   CcLayer()->SetBackdropFilters(filters.ReleaseCcFilterOperations());
   CcLayer()->SetBackdropFilterBounds(backdrop_filter_bounds);
 }
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.h b/third_party/blink/renderer/platform/graphics/graphics_layer.h
index 4e1fee1..6f8f489 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer.h
@@ -200,7 +200,7 @@
   }
 
   void SetFilters(CompositorFilterOperations);
-  void SetBackdropFilters(CompositorFilterOperations, const gfx::RectF&);
+  void SetBackdropFilters(CompositorFilterOperations, const gfx::RRectF&);
 
   void SetStickyPositionConstraint(const cc::LayerStickyPositionConstraint&);
 
diff --git a/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h b/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h
index 636a087..157b8aa 100644
--- a/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h
+++ b/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/platform/graphics/paint/paint_property_node.h"
 #include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
+#include "ui/gfx/rrect_f.h"
 
 namespace blink {
 
@@ -44,7 +45,7 @@
     CompositorFilterOperations filter;
     float opacity = 1;
     CompositorFilterOperations backdrop_filter;
-    gfx::RectF backdrop_filter_bounds;
+    gfx::RRectF backdrop_filter_bounds;
     SkBlendMode blend_mode = SkBlendMode::kSrcOver;
     // === End of effects ===
     CompositingReasons direct_compositing_reasons = CompositingReason::kNone;
@@ -132,7 +133,7 @@
     return state_.backdrop_filter;
   }
 
-  const gfx::RectF& BackdropFilterBounds() const {
+  const gfx::RRectF& BackdropFilterBounds() const {
     return state_.backdrop_filter_bounds;
   }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index ba60819..27c3a1b 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -340,12 +340,6 @@
       !RuntimeEnabledFeatures::WasmCodeCacheEnabled())
     return false;
 
-  // TODO(crbug.com/867347): Enable fetching of code caches on non-main threads
-  // once code cache has its own mojo interface. Currently it is using
-  // RenderMessageFilter that is not available on non-main threads.
-  if (!IsMainThread())
-    return false;
-
   const ResourceRequest& request = resource_->GetResourceRequest();
   if (!request.Url().ProtocolIsInHTTPFamily())
     return false;
@@ -1164,10 +1158,6 @@
     return;
   DCHECK_GE(response_out.ToResourceResponse().EncodedBodyLength(), 0);
 
-  // TODO(crbug.com/867347): Enable fetching of code caches synchronously
-  // once code cache has its own mojo interface. Currently it is using
-  // RenderMessageFilter that is not available on non-main threads.
-
   // Follow the async case convention of not calling DidReceiveData or
   // appending data to m_resource if the response body is empty. Copying the
   // empty buffer is a noop in most cases, but is destructive in the case of
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index c4ae1f9..5690db5 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -183,6 +183,7 @@
             'gfx::Point3F',
             'gfx::Rect',
             'gfx::RectF',
+            'gfx::RRectF',
             'gfx::Size',
             'gfx::SizeF',
             'gfx::Transform',
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index e998257..ca85451 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -92,8 +92,10 @@
 crbug.com/420008 virtual/threaded/http/tests/devtools/tracing/ [ Slow ]
 crbug.com/902685 http/tests/devtools/isolated-code-cache/same-origin-test.js [ Slow ]
 crbug.com/902685 http/tests/devtools/isolated-code-cache/cross-origin-test.js [ Slow ]
+crbug.com/902685 http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js [ Slow ]
 crbug.com/902685 virtual/site-isolated-code-cache/http/tests/devtools/isolated-code-cache/same-origin-test.js [ Slow ]
 crbug.com/902685 virtual/site-isolated-code-cache/http/tests/devtools/isolated-code-cache/cross-origin-test.js [ Slow ]
+crbug.com/902685 virtual/wasm-site-isolated-code-cache/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js [ Slow ]
 crbug.com/902685 virtual/not-site-per-process/http/tests/devtools/isolated-code-cache/same-origin-test.js [ Slow ]
 crbug.com/902685 virtual/not-site-per-process/http/tests/devtools/isolated-code-cache/cross-origin-test.js [ Slow ]
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 9f106e8..4e162ef9 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -519,6 +519,9 @@
 crbug.com/174167 external/wpt/css/css-tables/visibility-collapse-colspan-003.html [ Failure ]
 crbug.com/174167 external/wpt/css/css-tables/visibility-collapse-rowcol-001.html [ Failure ]
 crbug.com/174167 external/wpt/css/css-tables/visibility-collapse-rowcol-002.html [ Failure ]
+crbug.com/377847 external/wpt/css/css-tables/subpixel-table-cell-width-001.html [ Failure ]
+crbug.com/377847 external/wpt/css/css-tables/subpixel-table-cell-width-002.html [ Failure ]
+crbug.com/377847 external/wpt/css/css-tables/subpixel-table-width-001.html [ Failure ]
 
 # [css-contain]
 
@@ -1935,6 +1938,7 @@
 crbug.com/497522 css3/filters/backdrop-filter-bleeding.html [ Failure ]
 crbug.com/497522 css3/filters/backdrop-filter-svg.html [ Failure ]
 #crbug.com/497522 css3/filters/backdrop-filter-plus-filter.html [ Failure ]
+# This fails, but only in CAP mode:
 crbug.com/497522 css3/filters/backdrop-filter-rendering.html [ Failure ]
 crbug.com/497522 external/wpt/css/filter-effects/backdrop-filter-isolation-isolate.html [ Failure ]
 crbug.com/497522 external/wpt/css/filter-effects/backdrop-filter-border-radius.html [ Failure ]
@@ -3865,8 +3869,6 @@
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2j.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2k.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2l.html [ Failure ]
-crbug.com/626703 external/wpt/webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html [ Timeout ]
-crbug.com/626703 external/wpt/webaudio/the-audio-api/the-analysernode-interface/test-analyser-output.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-fonts/font-synthesis-01.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-fonts/font-synthesis-02.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-fonts/font-synthesis-03.html [ Failure ]
@@ -5750,7 +5752,7 @@
 
 # Sheriff 2018-11-23
 crbug.com/874162 virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-event-fired.html [ Skip ]
-crbug.com/906320 [ Mac10.13 ] virtual/not-site-per-process/http/tests/devtools/isolated-code-cache/same-origin-test.js [ Failure Pass ]
+crbug.com/906320 virtual/not-site-per-process/http/tests/devtools/isolated-code-cache/same-origin-test.js [ Failure Pass ]
 crbug.com/906320 [ Mac10.13 ] virtual/site-isolated-code-cache/http/tests/devtools/isolated-code-cache/same-origin-test.js [ Failure Pass ]
 
 # Sheriff 2018-11-26
@@ -5949,12 +5951,12 @@
 # Sheriff 2019-01-25
 crbug.com/925325 [ Mac ] storage/indexeddb/index-population.html [ Pass Failure ]
 
-crbug.com/v8/8319 external/wpt/wasm/jsapi/constructor/instantiate.any.html [ Failure ]
-crbug.com/v8/8319 external/wpt/wasm/jsapi/constructor/instantiate.any.worker.html [ Failure ]
-crbug.com/v8/8319 external/wpt/wasm/webapi/instantiateStreaming.any.html [ Failure ]
-crbug.com/v8/8319 external/wpt/wasm/webapi/instantiateStreaming.any.serviceworker.html [ Failure ]
-crbug.com/v8/8319 external/wpt/wasm/webapi/instantiateStreaming.any.sharedworker.html [ Failure ]
-crbug.com/v8/8319 external/wpt/wasm/webapi/instantiateStreaming.any.worker.html [ Failure ]
+crbug.com/926311 external/wpt/wasm/jsapi/constructor/instantiate.any.html [ Failure ]
+crbug.com/926311 external/wpt/wasm/jsapi/constructor/instantiate.any.worker.html [ Failure ]
+crbug.com/926311 external/wpt/wasm/webapi/instantiateStreaming.any.html [ Failure ]
+crbug.com/926311 external/wpt/wasm/webapi/instantiateStreaming.any.serviceworker.html [ Failure ]
+crbug.com/926311 external/wpt/wasm/webapi/instantiateStreaming.any.sharedworker.html [ Failure ]
+crbug.com/926311 external/wpt/wasm/webapi/instantiateStreaming.any.worker.html [ Failure ]
 
 crbug.com/v8/8319 external/wpt/wasm/jsapi/module/customSections.any.html [ Pass Failure ]
 crbug.com/v8/8319 external/wpt/wasm/jsapi/module/customSections.any.worker.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index cd250f7c..77893f7 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -778,6 +778,13 @@
              "--site-per-process"]
   },
   {
+    "prefix": "wasm-site-isolated-code-cache",
+    "base": "http/tests/devtools/wasm-isolated-code-cache",
+    "args": ["--enable-features=IsolatedCodeCache,WasmCodeCache",
+             "--disable-features=WebAssemblyBaseline",
+             "--site-per-process"]
+  },
+  {
     "prefix": "not-site-per-process",
     "base": "http/tests/devtools/isolated-code-cache",
     "args": ["--disable-site-isolation-trials"]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
index 4a9ce212..336c1ed 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -145945,11 +145945,6 @@
      {}
     ]
    ],
-   "css/css-transitions/events-004-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "css/css-transitions/idlharness-expected.txt": [
     [
      {}
@@ -156980,6 +156975,46 @@
      {}
     ]
    ],
+   "element-timing/resources/circle.svg": [
+    [
+     {}
+    ]
+   ],
+   "element-timing/resources/element-timing-helpers.js": [
+    [
+     {}
+    ]
+   ],
+   "element-timing/resources/iframe-with-square.html": [
+    [
+     {}
+    ]
+   ],
+   "element-timing/resources/progressive-image.py": [
+    [
+     {}
+    ]
+   ],
+   "element-timing/resources/slow-image.py": [
+    [
+     {}
+    ]
+   ],
+   "element-timing/resources/square100.png": [
+    [
+     {}
+    ]
+   ],
+   "element-timing/resources/square20.jpg": [
+    [
+     {}
+    ]
+   ],
+   "element-timing/resources/square20.png": [
+    [
+     {}
+    ]
+   ],
    "encoding/META.yml": [
     [
      {}
@@ -223660,6 +223695,66 @@
      }
     ]
    ],
+   "element-timing/buffer-before-onload.html": [
+    [
+     "/element-timing/buffer-before-onload.html",
+     {}
+    ]
+   ],
+   "element-timing/cross-origin-element.html": [
+    [
+     "/element-timing/cross-origin-element.html",
+     {}
+    ]
+   ],
+   "element-timing/cross-origin-iframe-element.html": [
+    [
+     "/element-timing/cross-origin-iframe-element.html",
+     {}
+    ]
+   ],
+   "element-timing/image-not-fully-visible.html": [
+    [
+     "/element-timing/image-not-fully-visible.html",
+     {}
+    ]
+   ],
+   "element-timing/observe-child-element.html": [
+    [
+     "/element-timing/observe-child-element.html",
+     {}
+    ]
+   ],
+   "element-timing/observe-elementtiming.html": [
+    [
+     "/element-timing/observe-elementtiming.html",
+     {}
+    ]
+   ],
+   "element-timing/observe-large-image.html": [
+    [
+     "/element-timing/observe-large-image.html",
+     {}
+    ]
+   ],
+   "element-timing/observe-multiple-images.html": [
+    [
+     "/element-timing/observe-multiple-images.html",
+     {}
+    ]
+   ],
+   "element-timing/progressively-loaded-image.html": [
+    [
+     "/element-timing/progressively-loaded-image.html",
+     {}
+    ]
+   ],
+   "element-timing/supported-element-type.html": [
+    [
+     "/element-timing/supported-element-type.html",
+     {}
+    ]
+   ],
    "encoding/api-basics.any.js": [
     [
      "/encoding/api-basics.any.html",
@@ -367502,7 +367597,7 @@
    "testharness"
   ],
   "css/css-transitions/KeyframeEffect-getKeyframes.tentative-expected.txt": [
-   "0eba18807185da9192cf58d168b2acd30358ebc0",
+   "30c5daca02330c2a881dd31f729eb5bdc23cf693",
    "support"
   ],
   "css/css-transitions/KeyframeEffect-getKeyframes.tentative.html": [
@@ -367565,10 +367660,6 @@
    "2f8ac7f4244ce95d9bc3eb64a322c026c0c1cad7",
    "testharness"
   ],
-  "css/css-transitions/events-004-expected.txt": [
-   "48c7fc897881b36e462353721764f039874f85d5",
-   "support"
-  ],
   "css/css-transitions/events-004.html": [
    "17195f40eb19d317de2ed877ce83127f82ea817c",
    "testharness"
@@ -391737,6 +391828,78 @@
    "7cd0be939f16e8aea7b00ff2b13a06102e26cc4d",
    "testharness"
   ],
+  "element-timing/buffer-before-onload.html": [
+   "4d59d4afc9f8e501a0a764cbce980d0d276250fe",
+   "testharness"
+  ],
+  "element-timing/cross-origin-element.html": [
+   "1b899b00e3abc5425bb8e97528c8635d6aabff75",
+   "testharness"
+  ],
+  "element-timing/cross-origin-iframe-element.html": [
+   "7f73881cc9726fa72c896fd1fbd1a496ade46695",
+   "testharness"
+  ],
+  "element-timing/image-not-fully-visible.html": [
+   "8ab3f343635a0e2c7704b4548b9b9dfa76388200",
+   "testharness"
+  ],
+  "element-timing/observe-child-element.html": [
+   "5bb8290893a7d80749e2dd03239c9c3f2f158b88",
+   "testharness"
+  ],
+  "element-timing/observe-elementtiming.html": [
+   "c148d33ab906da4588feea10370783b8c4b2404b",
+   "testharness"
+  ],
+  "element-timing/observe-large-image.html": [
+   "ef3eab8107b2824a60c955b54f58ef2cb4e4c3df",
+   "testharness"
+  ],
+  "element-timing/observe-multiple-images.html": [
+   "e56092c65bf4ab422875b54e25a5315d9f6da8c9",
+   "testharness"
+  ],
+  "element-timing/progressively-loaded-image.html": [
+   "6fdff39d53848546e113b72ca17e38fd9b0dabc7",
+   "testharness"
+  ],
+  "element-timing/resources/circle.svg": [
+   "209b9f4e5b5d55b45b5ec80dac25873d06dfb593",
+   "support"
+  ],
+  "element-timing/resources/element-timing-helpers.js": [
+   "0be97e403f27b4ab1e47fda1c114110c6e2a3edb",
+   "support"
+  ],
+  "element-timing/resources/iframe-with-square.html": [
+   "0a905d22b9a7d66271074163b57431ac75d29f7e",
+   "support"
+  ],
+  "element-timing/resources/progressive-image.py": [
+   "86ec8343658ee028a43a898308026082c93ef09e",
+   "support"
+  ],
+  "element-timing/resources/slow-image.py": [
+   "683160414a1120b09b4163c63fce82bb327d9f5f",
+   "support"
+  ],
+  "element-timing/resources/square100.png": [
+   "567babb96d1ec3e1032d476f8f7ee1fcb2aa4875",
+   "support"
+  ],
+  "element-timing/resources/square20.jpg": [
+   "83ed4914bbb52d097107bd6a128ae8e149b5be86",
+   "support"
+  ],
+  "element-timing/resources/square20.png": [
+   "4d51ac4b4633f0a24155f331ee63035e62b6dbe1",
+   "support"
+  ],
+  "element-timing/supported-element-type.html": [
+   "15733d46f95c9079acfec06cdd25f70ca0e056a6",
+   "testharness"
+  ],
   "encoding/META.yml": [
    "a219a492f0b963f19c50c094e9f00cf3cb69d467",
    "support"
@@ -418110,7 +418273,7 @@
    "support"
   ],
   "interfaces/proximity.idl": [
-   "3b0d240a2250a8c3ba6d78e17cca93162ee6715f",
+   "570a29fd37b09304871409dd811498fef8b3cf19",
    "support"
   ],
   "interfaces/push-api.idl": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-cell-width-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-cell-width-001-ref.html
new file mode 100644
index 0000000..ea2f38b6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-cell-width-001-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<style>
+  div {
+    font-size: 0; /* so I can leave spaces between the child divs */
+    height: 20px;
+  }
+  div > div {
+    display: inline-block;
+  }
+  div > div:first-child {
+    background: blue;
+  }
+  div > div:nth-child(2) {
+    background: lime;
+  }
+</style>
+
+<div>
+  <div style="width:3.6px;"></div>
+  <div style="width:3.6px;"></div>
+</div>
+
+<br><br>
+
+<div>
+  <div style="width:3.3px;"></div>
+  <div style="width:3.3px;"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-cell-width-001.html b/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-cell-width-001.html
new file mode 100644
index 0000000..2174fbec
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-cell-width-001.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<link rel="author" title="David Grogan" href="dgrogan@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS21/cascade.html#value-stages">
+<link rel="match" href="subpixel-table-cell-width-001-ref.html">
+<meta name="flags" content="" />
+<meta name="assert" content="When a cell has a specified fractional fixed width and a block has the same specified fractional width, their actual widths should match." />
+
+<style>
+.table {
+  display: table;
+  height: 20px;
+  background: red;
+}
+.cell {
+  display: table-cell;
+}
+div > div:first-child {
+  background: blue;
+}
+div > div:nth-child(2) {
+  background: lime;
+}
+</style>
+
+<div class=table>
+  <div class=cell style="width:3.6px;"></div>
+  <div class=cell style="width:3.6px;"></div>
+</div>
+
+<br><br>
+
+<div class=table>
+  <div class=cell style="width:3.3px;"></div>
+  <div class=cell style="width:3.3px;"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-cell-width-002.html b/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-cell-width-002.html
new file mode 100644
index 0000000..f47938f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-cell-width-002.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<link rel="author" title="David Grogan" href="dgrogan@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS21/cascade.html#value-stages">
+<link rel="match" href="subpixel-table-cell-width-001-ref.html">
+<meta name="flags" content="" />
+<meta name="assert" content="When a cell has a specified percent width that results in a fractional used width, the cell's actual width should match that of a block whose specified fixed width is the cell's used width" />
+
+<style>
+.table {
+  display: table;
+  height: 20px;
+  background: red;
+}
+.cell {
+  display: table-cell;
+}
+div > div:first-child {
+  background: blue;
+}
+div > div:nth-child(2) {
+  background: lime;
+}
+</style>
+
+
+<div class=table style="width:7.2px;">
+  <div class=cell style="width:50%;"></div>
+  <div class=cell style="width:50%;"></div>
+</div>
+
+<br><br>
+
+<div class=table style="width:6.6px;">
+  <div class=cell style="width:50%;"></div>
+  <div class=cell style="width:50%;"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-width-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-width-001-ref.html
new file mode 100644
index 0000000..277a327
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-width-001-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<style>
+.parent div {
+  background: #aaa;
+  width: 100%;
+  height: 100px;
+}
+</style>
+
+There should be two grey ~squares with no red showing.
+
+<div class="parent" style="width:100.2px">
+  <div></div>
+</div>
+
+<div class="parent" style="width:100.8px">
+  <div></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-width-001.html b/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-width-001.html
new file mode 100644
index 0000000..153282f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/subpixel-table-width-001.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/syndata.html#value-def-percentage">
+<link rel="match" href="subpixel-table-width-001-ref.html">
+<meta name="flags" content="" />
+<meta name="assert" content="A table with width:100% has same actual width as its parent's actual width." />
+
+<style>
+.parent {
+  background: red;
+}
+
+.parent table {
+  background: #aaa;
+  width: 100%;
+  height: 100px;
+}
+</style>
+
+There should be two grey ~squares with no red showing.
+
+<div class="parent" style="width:100.2px">
+  <table></table>
+</div>
+
+<div class="parent" style="width:100.8px">
+  <table></table>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius-ref.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius-ref.html
index eabcd99..e5712a23 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius-ref.html
@@ -5,7 +5,7 @@
 
 
 
-<div style="opacity: 0.9999;">
+<div>
   <div class="circle outside"></div>
   <div class="circle inside"></div>
 </div>
@@ -24,16 +24,13 @@
   top: 30px;
   left: 30px;
   border-radius: 50px;
-  background: yellow;
-  will-change: transform;
+  background: #ffff0060;
 }
 .inside {
-  background: #ffd94d;
+  background: #ffaf9f;
   clip-path: inset(0px 30px 30px 0px);
-  will-change: transform;
 }
 .outside {
-  background: #ffff4d;
-  will-change: transform;
+  background: #ffff9f;
 }
 </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius.html
index fc21250..ec93de6 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius.html
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius.html
@@ -24,11 +24,9 @@
   top: 30px;
   left: 30px;
   border-radius: 50px;
-  background: yellow;
-  will-change: transform;
+  background: #ffff0060;
 }
 .filter {
-  opacity: 0.7;
   backdrop-filter: invert(1);
 }
 </style>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.sub.html
new file mode 100644
index 0000000..ce31a81
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.sub.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/fetch/sec-metadata/resources/helper.js></script>
+<body>
+<script>
+  async_test(t => {
+    let i = document.createElement('iframe');
+    i.src = "http://{{host}}:{{ports[http][0]}}/fetch/sec-metadata/resources/post-to-owner.py";
+    window.addEventListener('message', t.step_func(e => {
+      if (e.source != i.contentWindow)
+        return;
+
+      assert_header_equals(e.data, {
+        "dest": "",
+        "site": "",
+        "user": ""
+      });
+      t.done();
+    }));
+
+    document.body.appendChild(i);
+  }, "Non-secure same-origin iframe => No headers");
+
+  async_test(t => {
+    let i = document.createElement('iframe');
+    i.src = "http://{{hosts[][www]}}:{{ports[http][0]}}/fetch/sec-metadata/resources/post-to-owner.py";
+    window.addEventListener('message', t.step_func(e => {
+      if (e.source != i.contentWindow)
+        return;
+
+      assert_header_equals(e.data, {
+        "dest": "",
+        "site": "",
+        "user": ""
+      });
+      t.done();
+    }));
+
+    document.body.appendChild(i);
+  }, "Non-secure same-site iframe => No headers");
+
+  async_test(t => {
+    let i = document.createElement('iframe');
+    i.src = "http://{{hosts[alt][www]}}:{{ports[http][0]}}/fetch/sec-metadata/resources/post-to-owner.py";
+    window.addEventListener('message', t.step_func(e => {
+      if (e.source != i.contentWindow)
+        return;
+
+      assert_header_equals(e.data, {
+        "dest": "",
+        "site": "",
+        "user": ""
+      });
+      t.done();
+    }));
+
+    document.body.appendChild(i);
+  }, "Non-secure cross-site iframe => No headers.");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/script.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/script.tentative.sub.html
new file mode 100644
index 0000000..482f4b9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/script.tentative.sub.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/fetch/sec-metadata/resources/helper.js></script>
+
+<!-- Same-origin script -->
+<script src="http://{{host}}:{{ports[http][0]}}/fetch/sec-metadata/resources/echo-as-script.py"></script>
+<script>
+  test(t => {
+    t.add_cleanup(_ => { header = null; });
+
+    assert_header_equals(header, {
+      "dest": "",
+      "site": "",
+      "user": ""
+    });
+  }, "Non-secure same-origin script => No headers");
+</script>
+
+<!-- Same-site script -->
+<script src="http://{{hosts[][www]}}:{{ports[http][0]}}/fetch/sec-metadata/resources/echo-as-script.py"></script>
+<script>
+  test(t => {
+    t.add_cleanup(_ => { header = null; });
+
+    assert_header_equals(header, {
+      "dest": "",
+      "site": "",
+      "user": ""
+    });
+  }, "Non-secure same-site script => No headers");
+</script>
+
+<!-- Cross-site script -->
+<script src="http://{{hosts[alt][www]}}:{{ports[http][0]}}/fetch/sec-metadata/resources/echo-as-script.py"></script>
+<script>
+  test(t => {
+    t.add_cleanup(_ => { header = null; });
+
+    assert_header_equals(header, {
+      "dest": "",
+      "site": "",
+      "user": ""
+    });
+  }, "Non-secure cross-site script => No headers");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/proximity.idl b/third_party/blink/web_tests/external/wpt/interfaces/proximity.idl
index 3b0d240..570a29f 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/proximity.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/proximity.idl
@@ -9,3 +9,9 @@
   readonly attribute double? max;
   readonly attribute boolean? near;
 };
+
+dictionary ProximityReadingValues {
+  required double? distance;
+  required double? max;
+  required boolean? near;
+};
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_click.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_click.html
index 77b5daae..341a82d 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_click.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_suppress_compat_events_on_click.html
@@ -27,7 +27,7 @@
       function end_of_interaction() {
           test(function () {
               assert_equals(event_log.join(", "),
-                  "mousedown@target1, mouseup@target1");
+                  "click@target0, mousedown@target1, mouseup@target1, click@target1");
           }, "Event log");
 
           test_pointerEvent.done(); // complete test
@@ -38,7 +38,7 @@
 
           var target_list = ["target0", "target1"];
           var pointer_event_list = ["pointerdown"];
-          var mouse_event_list = ["mousedown", "mouseup"];
+          var mouse_event_list = ["mousedown", "mouseup", "click"];
 
           target_list.forEach(function(targetId) {
               var target = document.getElementById(targetId);
@@ -95,7 +95,7 @@
   <body onload="run()">
     <h1>Pointer Event: Suppress compatibility mouse events on click</h1>
     <h4>
-      When a pointerdown is canceled, a click/tap shouldn't fire any compatibility mouse events.
+      When a pointerdown is canceled, a click/tap shouldn't fire any compatibility mouse events except click event.
     </h4>
     <ol>
       <li> Click or tap on Target0.</li>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/js/helpers.js b/third_party/blink/web_tests/external/wpt/webaudio/js/helpers.js
index fbbfc8e..5970b7b 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/js/helpers.js
+++ b/third_party/blink/web_tests/external/wpt/webaudio/js/helpers.js
@@ -159,8 +159,13 @@
     function testOnNormalContext(callback) {
       function testOutput(nodeToInspect, expectedBuffers, callback) {
         testLength = 0;
-        var sp = context.createScriptProcessor(expectedBuffers[0].length, gTest.numberOfChannels, 0);
-        nodeToInspect.connect(sp);
+        // While the spec allows ScriptProcessorNode's to have no outputs, it's
+        // not well specified, and Chrome requires the ScriptProcessorNode to
+        // be connected (directly or indirectly) to the destination.  So make it
+        // so.  This doesn't affect the tests using the function because the
+        // ScriptProcessorNode is what verifies the test.
+        var sp = context.createScriptProcessor(expectedBuffers[0].length, gTest.numberOfChannels, 1);
+        nodeToInspect.connect(sp).connect(context.destination);
         sp.onaudioprocess = function(e) {
           var expectedBuffer = expectedBuffers.shift();
           testLength += expectedBuffer.length;
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html
index 62d90da1..1b5531b 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-analysernode-interface/test-analyser-minimum.html
@@ -10,13 +10,17 @@
     var ac = new AudioContext();
     var analyser = ac.createAnalyser();
     var constant = ac.createConstantSource();
-    var sp = ac.createScriptProcessor(2048, 1, 0);
+    // Chrome requires a ScriptProcessorNode to be connected to destination
+    // (directly or indirectly), so create the node with one output and connect
+    // it to the destination.  This doesn't affect the test because the
+    // ScriptProcessorNode itself verifies the results.
+    var sp = ac.createScriptProcessor(2048, 1, 1);
 
     constant.offset.value = 0.0;
 
     constant.connect(analyser).connect(ac.destination);
 
-    constant.connect(sp);
+    constant.connect(sp).connect(ac.destination);
 
     var buf = new Float32Array(analyser.frequencyBinCount);
     var iteration_count = 10;
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-self-baseline-04-expected.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-self-baseline-04-expected.html
index 72df5ff..f20b2bb 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-self-baseline-04-expected.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-self-baseline-04-expected.html
@@ -43,7 +43,7 @@
 }
 </style>
 
-<p>1x4 with parallel and orthogonal items. Items orthogonal to the baseline-axis will use a synthesized baseline (border-box 'under' edge).<br>All items share 'first-row' Baseline Context. No item shares any column-like Baseline Context.<br>The 'align-self' property (orthogonal to the shared context) aligns all items along the baseline-axis using the row-like baseline.</p>
+<p>1x4 with parallel and orthogonal items. Items orthogonal to the baseline-axis will use a synthesized baseline (border-box 'under' edge).<br>All items share 'first-row' Baseline Context. No item shares any column-like Baseline Context.<br>The 'align-self' property (orthogonal to the shared context) aligns all the items along the baseline-axis using the row-like baseline.</p>
 <div class="block"><div class="area"><div class="item">A</div></div><div class="area verticalLR"><div class="item">A</div></div><div class="area"><div class="item">A</div></div><div class="area verticalLR"><div class="item">A</div></div></div>
 <div class="block"><div class="area"><div class="item extraBottomPadding">A</div></div><div class="area verticalLR"><div class="item extraTopPadding">A</div></div><div class="area"><div class="item">A</div></div><div class="area verticalLR top"><div class="item">A</div></div></div>
 
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-self-baseline-04.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-self-baseline-04.html
index 05644f7d..3166d15 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-self-baseline-04.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-self-baseline-04.html
@@ -28,7 +28,7 @@
 </style>
 
 
-<p>1x4 with parallel and orthogonal items. Items orthogonal to the baseline-axis will use a synthesized baseline (border-box 'under' edge).<br>All items share 'first-row' Baseline Context. No item shares any column-like Baseline Context.<br>The 'align-self' property (orthogonal to the shared context) aligns all items along the baseline-axis using the row-like baseline.</p>
+<p>1x4 with parallel and orthogonal items. Items orthogonal to the baseline-axis will use a synthesized baseline (border-box 'under' edge).<br>All items share 'first-row' Baseline Context. No item shares any column-like Baseline Context.<br>The 'align-self' property (orthogonal to the shared context) aligns all the items along the baseline-axis using the row-like baseline.</p>
 <div class="block grid contentStart justifyItemsStart alignItemsBaseline"><div class="item">A</div><div class="item verticalLR">A</div><div class="item">A</div><div class="item verticalLR">A</div></div>
 <div class="block grid contentStart justifyItemsStart alignItemsBaseline"><div class="item extraBottomPadding">A</div><div class="item verticalLR  extraTopPadding">A</div><div class="item">A</div><div class="item verticalLR">A</div></div>
 
diff --git a/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-getSettings.html b/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-getSettings.html
index da405fe..e223c52 100644
--- a/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-getSettings.html
+++ b/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-getSettings.html
@@ -34,7 +34,7 @@
                 'Noise suppression missing: ' + JSON.stringify(settings));
     assert_true('echoCancellationType' in settings,
                 'Echo cancellation type missing: ' + JSON.stringify(settings));
-    assert_in_array(settings.echoCancellationType, [ "browser", "system" ],
+    assert_in_array(settings.echoCancellationType, [ "aec3", "system" ],
                 'Echo cancellation type invalid: ' + JSON.stringify(settings));
   });
 }, 'An audio track returns the expected variables');
diff --git a/third_party/blink/web_tests/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test-expected.txt b/third_party/blink/web_tests/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test-expected.txt
new file mode 100644
index 0000000..4b10d7a
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test-expected.txt
@@ -0,0 +1,88 @@
+Tests V8 code cache for WebAssembly resources.
+
+---First navigation - produce and consume code cache ------
+
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+
+--- Second navigation - from a different origin ------
+
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js b/third_party/blink/web_tests/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js
new file mode 100644
index 0000000..8d90680
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js
@@ -0,0 +1,85 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests V8 code cache for WebAssembly resources.\n`);
+  await TestRunner.loadModule('performance_test_runner');
+  await TestRunner.showPanel('timeline');
+
+  // Clear browser cache to avoid any existing entries for the fetched
+  // scripts in the cache.
+  SDK.multitargetNetworkManager.clearBrowserCache();
+
+  function runTests() {
+    // Loads a WASM module that is smaller than the threshold twice. It should
+    // compile and not be cached.
+    function loadSmallWasmModule(iframe_window) {
+      const url = 'http://127.0.0.1:8000/wasm/resources/load-wasm.php?name=small.wasm&cors'
+      return iframe_window.instantiateModule(url)
+        .then(() => iframe_window.instantiateModule(url));
+    }
+    // Loads a WASM module that is larger than the caching threshold. It
+    // should be cached the first run and bypass compilation the second.
+    function loadLargeWasmModule(iframe_window) {
+      const url = 'http://127.0.0.1:8000/wasm/resources/load-wasm.php?name=large.wasm&cors'
+      return iframe_window.instantiateModule(url)
+        .then(() => iframe_window.instantiateModule(url));
+    }
+    // Load the same large WASM module with a different URL. It should miss
+    // the cache, compile and be cached.
+    function loadOtherLargeWasmModule(iframe_window) {
+      const url = 'http://localhost:8000/wasm/resources/load-wasm.php?name=large.wasm&cors'
+      return iframe_window.instantiateModule(url);
+    }
+
+    let script = document.createElement('script');
+    script.type = 'module';
+    script.text = 'window.finishTest()';
+    document.body.appendChild(script);
+
+    const frameId = 'frame_id';
+    const iframe_window = document.getElementById(frameId).contentWindow;
+
+    // These functions must be called in this order.
+    return loadSmallWasmModule(iframe_window)
+      .then(() => loadLargeWasmModule(iframe_window))
+      .then(() => loadOtherLargeWasmModule(iframe_window));
+  }
+
+  await TestRunner.evaluateInPagePromise(runTests.toString());
+
+  TestRunner.addResult(
+      '---First navigation - produce and consume code cache ------\n');
+
+  // Create a same origin iframe.
+  const scope = 'http://127.0.0.1:8000/wasm/resources/wasm-cache-iframe.html';
+  await TestRunner.addIframe(scope, {id: 'frame_id'});
+
+  await PerformanceTestRunner.invokeAsyncWithTimeline('runTests');
+
+  const events = new Set([
+    TimelineModel.TimelineModel.RecordType.WasmStreamFromResponseCallback,
+    TimelineModel.TimelineModel.RecordType.WasmCompiledModule,
+    TimelineModel.TimelineModel.RecordType.WasmCachedModule,
+    TimelineModel.TimelineModel.RecordType.WasmModuleCacheHit,
+    TimelineModel.TimelineModel.RecordType.WasmModuleCacheInvalid]);
+  const tracingModel = PerformanceTestRunner.tracingModel();
+
+  tracingModel.sortedProcesses().forEach(p => p.sortedThreads().forEach(t =>
+      t.events().filter(event => events.has(event.name)).forEach(PerformanceTestRunner.printTraceEventProperties)));
+
+  // Second navigation
+  TestRunner.addResult(
+      '\n--- Second navigation - from a different origin ------\n');
+
+  const other_scope = 'http://localhost:8000/wasm/resources/wasm-cache-iframe.html';
+  await TestRunner.addIframe(other_scope, {id: 'frame_id'});
+
+  await PerformanceTestRunner.invokeAsyncWithTimeline('runTests');
+
+  tracingModel.sortedProcesses().forEach(p => p.sortedThreads().forEach(t =>
+      t.events().filter(event => events.has(event.name)).forEach(PerformanceTestRunner.printTraceEventProperties)));
+
+  TestRunner.completeTest();
+})();
diff --git a/third_party/blink/web_tests/http/tests/wasm/resources/large.wasm b/third_party/blink/web_tests/http/tests/wasm/resources/large.wasm
new file mode 100644
index 0000000..fe5e206
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/wasm/resources/large.wasm
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/wasm/resources/load-wasm.php b/third_party/blink/web_tests/http/tests/wasm/resources/load-wasm.php
index 9b1ac01..14967b9 100644
--- a/third_party/blink/web_tests/http/tests/wasm/resources/load-wasm.php
+++ b/third_party/blink/web_tests/http/tests/wasm/resources/load-wasm.php
@@ -4,7 +4,16 @@
     if (isset($_GET['name'])) {
        $fileName = $_GET['name'];
     }
+    $last_modified = "Tue, 18 Dec 2018 23:15:53 GMT";
+    if (isset($_GET['last-modified'])) {
+       $last_modified = $_GET['last-modified'];
+    }
 
     header("Content-Type: application/wasm");
+    header("Last-Modified: ".$last_modified);
+
+    if (isset($_GET['cors'])) {
+      header("Access-Control-Allow-Origin: *");
+    }
     require($fileName);
 ?>
diff --git a/third_party/blink/web_tests/http/tests/wasm/resources/small.wasm b/third_party/blink/web_tests/http/tests/wasm/resources/small.wasm
new file mode 100644
index 0000000..f8b2262
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/wasm/resources/small.wasm
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/wasm/resources/wasm-cache-iframe.html b/third_party/blink/web_tests/http/tests/wasm/resources/wasm-cache-iframe.html
new file mode 100644
index 0000000..8a62a7aa
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/wasm/resources/wasm-cache-iframe.html
@@ -0,0 +1,10 @@
+<script src="../../../resources/testharness.js"></script>
+<script>
+// Instantiate a WASM test module and make sure it works.
+function instantiateModule(url)
+{
+  return WebAssembly.instantiateStreaming(fetch(url)).then(
+  	({module, instance}) => assert_equals(instance.exports.exported_func(), 42));
+}
+</script>
+
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child-expected.txt
new file mode 100644
index 0000000..19f391b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child-expected.txt
@@ -0,0 +1,50 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutBlockFlow DIV class='blur'",
+      "position": [8, 8],
+      "bounds": [200, 200]
+    },
+    {
+      "name": "LayoutBlockFlow DIV class='accelerated'",
+      "bounds": [212, 257],
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow DIV id='resize' class='drop-shadow'",
+          "rect": [0, 0, 212, 257],
+          "reason": "geometry"
+        }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-4, -4, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child-expected.txt
new file mode 100644
index 0000000..19f391b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child-expected.txt
@@ -0,0 +1,50 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutBlockFlow DIV class='blur'",
+      "position": [8, 8],
+      "bounds": [200, 200]
+    },
+    {
+      "name": "LayoutBlockFlow DIV class='accelerated'",
+      "bounds": [212, 257],
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow DIV id='resize' class='drop-shadow'",
+          "rect": [0, 0, 212, 257],
+          "reason": "geometry"
+        }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-4, -4, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/virtual/wasm-site-isolated-code-cache/http/tests/devtools/wasm-isolated-code-cache/README.txt b/third_party/blink/web_tests/virtual/wasm-site-isolated-code-cache/http/tests/devtools/wasm-isolated-code-cache/README.txt
new file mode 100644
index 0000000..4ebf844
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/wasm-site-isolated-code-cache/http/tests/devtools/wasm-isolated-code-cache/README.txt
@@ -0,0 +1,4 @@
+# This suite runs the tests in http/tests/devtools/wasm-isolated-code-cache with
+# --enable-features=IsolatedCodeCache,WasmCodeCache --site-per-process.
+# This feature is required for security to enforce site isolation on V8
+# code caches. Tracking bug: crbug.com/812168
diff --git a/third_party/blink/web_tests/virtual/wasm-site-isolated-code-cache/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test-expected.txt b/third_party/blink/web_tests/virtual/wasm-site-isolated-code-cache/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test-expected.txt
new file mode 100644
index 0000000..c0d97ff
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/wasm-site-isolated-code-cache/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test-expected.txt
@@ -0,0 +1,216 @@
+Tests V8 code cache for WebAssembly resources.
+
+---First navigation - produce and consume code cache ------
+
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.compiledModule Properties:
+{
+    data : {
+        url : http://127.0.0.1:8000/wasm/resources/load-wasm.php?name=small.wasm&cors
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.compiledModule"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.compiledModule Properties:
+{
+    data : {
+        url : http://127.0.0.1:8000/wasm/resources/load-wasm.php?name=small.wasm&cors
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.compiledModule"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.compiledModule Properties:
+{
+    data : {
+        url : http://127.0.0.1:8000/wasm/resources/load-wasm.php?name=large.wasm&cors
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.compiledModule"
+}
+v8.wasm.cachedModule Properties:
+{
+    data : {
+        producedCacheSize : <number>
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.cachedModule"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.moduleCacheHit Properties:
+{
+    data : {
+        consumedCacheSize : <number>
+        url : http://127.0.0.1:8000/wasm/resources/load-wasm.php?name=large.wasm&cors
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.moduleCacheHit"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.compiledModule Properties:
+{
+    data : {
+        url : http://localhost:8000/wasm/resources/load-wasm.php?name=large.wasm&cors
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.compiledModule"
+}
+v8.wasm.cachedModule Properties:
+{
+    data : {
+        producedCacheSize : <number>
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.cachedModule"
+}
+
+--- Second navigation - from a different origin ------
+
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.compiledModule Properties:
+{
+    data : {
+        url : http://127.0.0.1:8000/wasm/resources/load-wasm.php?name=small.wasm&cors
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.compiledModule"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.compiledModule Properties:
+{
+    data : {
+        url : http://127.0.0.1:8000/wasm/resources/load-wasm.php?name=small.wasm&cors
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.compiledModule"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.compiledModule Properties:
+{
+    data : {
+        url : http://127.0.0.1:8000/wasm/resources/load-wasm.php?name=large.wasm&cors
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.compiledModule"
+}
+v8.wasm.cachedModule Properties:
+{
+    data : {
+        producedCacheSize : <number>
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.cachedModule"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.moduleCacheHit Properties:
+{
+    data : {
+        consumedCacheSize : <number>
+        url : http://127.0.0.1:8000/wasm/resources/load-wasm.php?name=large.wasm&cors
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.moduleCacheHit"
+}
+v8.wasm.streamFromResponseCallback Properties:
+{
+    data : {
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.streamFromResponseCallback"
+}
+v8.wasm.compiledModule Properties:
+{
+    data : {
+        url : http://localhost:8000/wasm/resources/load-wasm.php?name=large.wasm&cors
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.compiledModule"
+}
+v8.wasm.cachedModule Properties:
+{
+    data : {
+        producedCacheSize : <number>
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.wasm.cachedModule"
+}
+
diff --git a/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider.dlldata.c b/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider.dlldata.c
new file mode 100644
index 0000000..da368593
--- /dev/null
+++ b/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider.dlldata.c
@@ -0,0 +1,37 @@
+/*********************************************************

+   DllData file -- generated by MIDL compiler 

+

+        DO NOT ALTER THIS FILE

+

+   This file is regenerated by MIDL on every IDL file compile.

+

+   To completely reconstruct this file, delete it and rerun MIDL

+   on all the IDL files in this DLL, specifying this file for the

+   /dlldata command line option

+

+*********************************************************/

+

+

+#include <rpcproxy.h>

+

+#ifdef __cplusplus

+extern "C"   {

+#endif

+

+EXTERN_PROXY_FILE( gaia_credential_provider )

+

+

+PROXYFILE_LIST_START

+/* Start of list */

+  REFERENCE_PROXY_FILE( gaia_credential_provider ),

+/* End of list */

+PROXYFILE_LIST_END

+

+

+DLLDATA_ROUTINES( aProxyFileList, GET_DLL_CLSID )

+

+#ifdef __cplusplus

+}  /*extern "C" */

+#endif

+

+/* end of generated dlldata file */

diff --git a/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider.tlb b/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider.tlb
new file mode 100644
index 0000000..9ded74a
--- /dev/null
+++ b/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider.tlb
Binary files differ
diff --git a/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider_i.c b/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider_i.c
new file mode 100644
index 0000000..a225804
--- /dev/null
+++ b/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider_i.c
@@ -0,0 +1,94 @@
+

+

+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */

+

+/* link this file in with the server and any clients */

+

+

+ /* File created by MIDL compiler version 8.xx.xxxx */

+/* at a redacted point in time

+ */

+/* Compiler settings for gen/chrome/credential_provider/gaiacp/gaia_credential_provider.idl:

+    Oicf, W1, Zp8, env=Win64 (32b run), target_arch=ARM64 8.01.0622 

+    protocol : dce , ms_ext, c_ext, robust

+    error checks: allocation ref bounds_check enum stub_data 

+    VC __declspec() decoration level: 

+         __declspec(uuid()), __declspec(selectany), __declspec(novtable)

+         DECLSPEC_UUID(), MIDL_INTERFACE()

+*/

+/* @@MIDL_FILE_HEADING(  ) */

+

+#pragma warning( disable: 4049 )  /* more than 64k source lines */

+

+

+#ifdef __cplusplus

+extern "C"{

+#endif 

+

+

+#include <rpc.h>

+#include <rpcndr.h>

+

+#ifdef _MIDL_USE_GUIDDEF_

+

+#ifndef INITGUID

+#define INITGUID

+#include <guiddef.h>

+#undef INITGUID

+#else

+#include <guiddef.h>

+#endif

+

+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \

+        DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)

+

+#else // !_MIDL_USE_GUIDDEF_

+

+#ifndef __IID_DEFINED__

+#define __IID_DEFINED__

+

+typedef struct _IID

+{

+    unsigned long x;

+    unsigned short s1;

+    unsigned short s2;

+    unsigned char  c[8];

+} IID;

+

+#endif // __IID_DEFINED__

+

+#ifndef CLSID_DEFINED

+#define CLSID_DEFINED

+typedef IID CLSID;

+#endif // CLSID_DEFINED

+

+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \

+        EXTERN_C __declspec(selectany) const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}

+

+#endif // !_MIDL_USE_GUIDDEF_

+

+MIDL_DEFINE_GUID(IID, IID_IGaiaCredentialProvider,0xCEC9EF6C,0xB2E6,0x4BB6,0x8F,0x1E,0x17,0x47,0xBA,0x4F,0x71,0x38);

+

+

+MIDL_DEFINE_GUID(IID, IID_IGaiaCredentialProviderForTesting,0x224CE2FB,0x2977,0x4585,0xBD,0x46,0x1B,0xAE,0x8D,0x79,0x64,0xDE);

+

+

+MIDL_DEFINE_GUID(IID, IID_IGaiaCredential,0xE5BF88DF,0x9966,0x465B,0xB2,0x33,0xC1,0xCA,0xC7,0x51,0x0A,0x59);

+

+

+MIDL_DEFINE_GUID(IID, IID_IReauthCredential,0xCC75BCEA,0xA636,0x4798,0xBF,0x8E,0x0F,0xF6,0x4D,0x74,0x34,0x51);

+

+

+MIDL_DEFINE_GUID(IID, LIBID_GaiaCredentialProviderLib,0x4ADC3A52,0x8673,0x4CE3,0x81,0xF6,0x83,0x3D,0x18,0xBE,0xEB,0xA2);

+

+

+MIDL_DEFINE_GUID(CLSID, CLSID_GaiaCredentialProvider,0x89adae71,0xaee5,0x4ee2,0xbf,0xfb,0xe8,0x42,0x4e,0x06,0xf5,0x19);

+

+#undef MIDL_DEFINE_GUID

+

+#ifdef __cplusplus

+}

+#endif

+

+

+

diff --git a/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider_i.h b/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider_i.h
new file mode 100644
index 0000000..b1be120
--- /dev/null
+++ b/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider_i.h
@@ -0,0 +1,529 @@
+

+

+/* this ALWAYS GENERATED file contains the definitions for the interfaces */

+

+

+ /* File created by MIDL compiler version 8.xx.xxxx */

+/* at a redacted point in time

+ */

+/* Compiler settings for gen/chrome/credential_provider/gaiacp/gaia_credential_provider.idl:

+    Oicf, W1, Zp8, env=Win64 (32b run), target_arch=ARM64 8.01.0622 

+    protocol : dce , ms_ext, c_ext, robust

+    error checks: allocation ref bounds_check enum stub_data 

+    VC __declspec() decoration level: 

+         __declspec(uuid()), __declspec(selectany), __declspec(novtable)

+         DECLSPEC_UUID(), MIDL_INTERFACE()

+*/

+/* @@MIDL_FILE_HEADING(  ) */

+

+#pragma warning( disable: 4049 )  /* more than 64k source lines */

+

+

+/* verify that the <rpcndr.h> version is high enough to compile this file*/

+#ifndef __REQUIRED_RPCNDR_H_VERSION__

+#define __REQUIRED_RPCNDR_H_VERSION__ 475

+#endif

+

+#include "rpc.h"

+#include "rpcndr.h"

+

+#ifndef __RPCNDR_H_VERSION__

+#error this stub requires an updated version of <rpcndr.h>

+#endif /* __RPCNDR_H_VERSION__ */

+

+#ifndef COM_NO_WINDOWS_H

+#include "windows.h"

+#include "ole2.h"

+#endif /*COM_NO_WINDOWS_H*/

+

+#ifndef __gaia_credential_provider_i_h__

+#define __gaia_credential_provider_i_h__

+

+#if defined(_MSC_VER) && (_MSC_VER >= 1020)

+#pragma once

+#endif

+

+/* Forward Declarations */ 

+

+#ifndef __IGaiaCredentialProvider_FWD_DEFINED__

+#define __IGaiaCredentialProvider_FWD_DEFINED__

+typedef interface IGaiaCredentialProvider IGaiaCredentialProvider;

+

+#endif 	/* __IGaiaCredentialProvider_FWD_DEFINED__ */

+

+

+#ifndef __IGaiaCredentialProviderForTesting_FWD_DEFINED__

+#define __IGaiaCredentialProviderForTesting_FWD_DEFINED__

+typedef interface IGaiaCredentialProviderForTesting IGaiaCredentialProviderForTesting;

+

+#endif 	/* __IGaiaCredentialProviderForTesting_FWD_DEFINED__ */

+

+

+#ifndef __IGaiaCredential_FWD_DEFINED__

+#define __IGaiaCredential_FWD_DEFINED__

+typedef interface IGaiaCredential IGaiaCredential;

+

+#endif 	/* __IGaiaCredential_FWD_DEFINED__ */

+

+

+#ifndef __IReauthCredential_FWD_DEFINED__

+#define __IReauthCredential_FWD_DEFINED__

+typedef interface IReauthCredential IReauthCredential;

+

+#endif 	/* __IReauthCredential_FWD_DEFINED__ */

+

+

+#ifndef __GaiaCredentialProvider_FWD_DEFINED__

+#define __GaiaCredentialProvider_FWD_DEFINED__

+

+#ifdef __cplusplus

+typedef class GaiaCredentialProvider GaiaCredentialProvider;

+#else

+typedef struct GaiaCredentialProvider GaiaCredentialProvider;

+#endif /* __cplusplus */

+

+#endif 	/* __GaiaCredentialProvider_FWD_DEFINED__ */

+

+

+/* header files for imported files */

+#include "oaidl.h"

+#include "ocidl.h"

+

+#ifdef __cplusplus

+extern "C"{

+#endif 

+

+

+#ifndef __IGaiaCredentialProvider_INTERFACE_DEFINED__

+#define __IGaiaCredentialProvider_INTERFACE_DEFINED__

+

+/* interface IGaiaCredentialProvider */

+/* [unique][uuid][object] */ 

+

+

+EXTERN_C const IID IID_IGaiaCredentialProvider;

+

+#if defined(__cplusplus) && !defined(CINTERFACE)

+    

+    MIDL_INTERFACE("CEC9EF6C-B2E6-4BB6-8F1E-1747BA4F7138")

+    IGaiaCredentialProvider : public IUnknown

+    {

+    public:

+        virtual HRESULT STDMETHODCALLTYPE OnUserAuthenticated( 

+            /* [in] */ IUnknown *credential,

+            /* [in] */ BSTR username,

+            /* [in] */ BSTR password,

+            /* [in] */ BSTR sid,

+            /* [in] */ BOOL fire_credentials_changed) = 0;

+        

+        virtual HRESULT STDMETHODCALLTYPE HasInternetConnection( void) = 0;

+        

+    };

+    

+    

+#else 	/* C style interface */

+

+    typedef struct IGaiaCredentialProviderVtbl

+    {

+        BEGIN_INTERFACE

+        

+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 

+            IGaiaCredentialProvider * This,

+            /* [in] */ REFIID riid,

+            /* [annotation][iid_is][out] */ 

+            _COM_Outptr_  void **ppvObject);

+        

+        ULONG ( STDMETHODCALLTYPE *AddRef )( 

+            IGaiaCredentialProvider * This);

+        

+        ULONG ( STDMETHODCALLTYPE *Release )( 

+            IGaiaCredentialProvider * This);

+        

+        HRESULT ( STDMETHODCALLTYPE *OnUserAuthenticated )( 

+            IGaiaCredentialProvider * This,

+            /* [in] */ IUnknown *credential,

+            /* [in] */ BSTR username,

+            /* [in] */ BSTR password,

+            /* [in] */ BSTR sid,

+            /* [in] */ BOOL fire_credentials_changed);

+        

+        HRESULT ( STDMETHODCALLTYPE *HasInternetConnection )( 

+            IGaiaCredentialProvider * This);

+        

+        END_INTERFACE

+    } IGaiaCredentialProviderVtbl;

+

+    interface IGaiaCredentialProvider

+    {

+        CONST_VTBL struct IGaiaCredentialProviderVtbl *lpVtbl;

+    };

+

+    

+

+#ifdef COBJMACROS

+

+

+#define IGaiaCredentialProvider_QueryInterface(This,riid,ppvObject)	\

+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 

+

+#define IGaiaCredentialProvider_AddRef(This)	\

+    ( (This)->lpVtbl -> AddRef(This) ) 

+

+#define IGaiaCredentialProvider_Release(This)	\

+    ( (This)->lpVtbl -> Release(This) ) 

+

+

+#define IGaiaCredentialProvider_OnUserAuthenticated(This,credential,username,password,sid,fire_credentials_changed)	\

+    ( (This)->lpVtbl -> OnUserAuthenticated(This,credential,username,password,sid,fire_credentials_changed) ) 

+

+#define IGaiaCredentialProvider_HasInternetConnection(This)	\

+    ( (This)->lpVtbl -> HasInternetConnection(This) ) 

+

+#endif /* COBJMACROS */

+

+

+#endif 	/* C style interface */

+

+

+

+

+#endif 	/* __IGaiaCredentialProvider_INTERFACE_DEFINED__ */

+

+

+/* interface __MIDL_itf_gaia_credential_provider_0000_0001 */

+/* [local] */ 

+

+typedef /* [public][public] */ 

+enum __MIDL___MIDL_itf_gaia_credential_provider_0000_0001_0001

+    {

+        kHicForceYes	= 0,

+        kHicForceNo	= ( kHicForceYes + 1 ) ,

+        kHicCheckAlways	= ( kHicForceNo + 1 ) 

+    } 	HasInternetConnectionCheckType;

+

+

+

+extern RPC_IF_HANDLE __MIDL_itf_gaia_credential_provider_0000_0001_v0_0_c_ifspec;

+extern RPC_IF_HANDLE __MIDL_itf_gaia_credential_provider_0000_0001_v0_0_s_ifspec;

+

+#ifndef __IGaiaCredentialProviderForTesting_INTERFACE_DEFINED__

+#define __IGaiaCredentialProviderForTesting_INTERFACE_DEFINED__

+

+/* interface IGaiaCredentialProviderForTesting */

+/* [unique][uuid][object] */ 

+

+

+EXTERN_C const IID IID_IGaiaCredentialProviderForTesting;

+

+#if defined(__cplusplus) && !defined(CINTERFACE)

+    

+    MIDL_INTERFACE("224CE2FB-2977-4585-BD46-1BAE8D7964DE")

+    IGaiaCredentialProviderForTesting : public IUnknown

+    {

+    public:

+        virtual HRESULT STDMETHODCALLTYPE SetHasInternetConnection( 

+            /* [in] */ HasInternetConnectionCheckType hic) = 0;

+        

+    };

+    

+    

+#else 	/* C style interface */

+

+    typedef struct IGaiaCredentialProviderForTestingVtbl

+    {

+        BEGIN_INTERFACE

+        

+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 

+            IGaiaCredentialProviderForTesting * This,

+            /* [in] */ REFIID riid,

+            /* [annotation][iid_is][out] */ 

+            _COM_Outptr_  void **ppvObject);

+        

+        ULONG ( STDMETHODCALLTYPE *AddRef )( 

+            IGaiaCredentialProviderForTesting * This);

+        

+        ULONG ( STDMETHODCALLTYPE *Release )( 

+            IGaiaCredentialProviderForTesting * This);

+        

+        HRESULT ( STDMETHODCALLTYPE *SetHasInternetConnection )( 

+            IGaiaCredentialProviderForTesting * This,

+            /* [in] */ HasInternetConnectionCheckType hic);

+        

+        END_INTERFACE

+    } IGaiaCredentialProviderForTestingVtbl;

+

+    interface IGaiaCredentialProviderForTesting

+    {

+        CONST_VTBL struct IGaiaCredentialProviderForTestingVtbl *lpVtbl;

+    };

+

+    

+

+#ifdef COBJMACROS

+

+

+#define IGaiaCredentialProviderForTesting_QueryInterface(This,riid,ppvObject)	\

+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 

+

+#define IGaiaCredentialProviderForTesting_AddRef(This)	\

+    ( (This)->lpVtbl -> AddRef(This) ) 

+

+#define IGaiaCredentialProviderForTesting_Release(This)	\

+    ( (This)->lpVtbl -> Release(This) ) 

+

+

+#define IGaiaCredentialProviderForTesting_SetHasInternetConnection(This,hic)	\

+    ( (This)->lpVtbl -> SetHasInternetConnection(This,hic) ) 

+

+#endif /* COBJMACROS */

+

+

+#endif 	/* C style interface */

+

+

+

+

+#endif 	/* __IGaiaCredentialProviderForTesting_INTERFACE_DEFINED__ */

+

+

+#ifndef __IGaiaCredential_INTERFACE_DEFINED__

+#define __IGaiaCredential_INTERFACE_DEFINED__

+

+/* interface IGaiaCredential */

+/* [unique][uuid][object] */ 

+

+

+EXTERN_C const IID IID_IGaiaCredential;

+

+#if defined(__cplusplus) && !defined(CINTERFACE)

+    

+    MIDL_INTERFACE("E5BF88DF-9966-465B-B233-C1CAC7510A59")

+    IGaiaCredential : public IUnknown

+    {

+    public:

+        virtual HRESULT STDMETHODCALLTYPE Initialize( 

+            /* [in] */ IGaiaCredentialProvider *provider) = 0;

+        

+        virtual HRESULT STDMETHODCALLTYPE Terminate( void) = 0;

+        

+        virtual HRESULT STDMETHODCALLTYPE OnUserAuthenticated( 

+            /* [in] */ BSTR authentication_info,

+            /* [out] */ BSTR *status_text) = 0;

+        

+        virtual HRESULT STDMETHODCALLTYPE ReportError( 

+            /* [in] */ LONG status,

+            /* [in] */ LONG substatus,

+            /* [in] */ BSTR status_text) = 0;

+        

+    };

+    

+    

+#else 	/* C style interface */

+

+    typedef struct IGaiaCredentialVtbl

+    {

+        BEGIN_INTERFACE

+        

+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 

+            IGaiaCredential * This,

+            /* [in] */ REFIID riid,

+            /* [annotation][iid_is][out] */ 

+            _COM_Outptr_  void **ppvObject);

+        

+        ULONG ( STDMETHODCALLTYPE *AddRef )( 

+            IGaiaCredential * This);

+        

+        ULONG ( STDMETHODCALLTYPE *Release )( 

+            IGaiaCredential * This);

+        

+        HRESULT ( STDMETHODCALLTYPE *Initialize )( 

+            IGaiaCredential * This,

+            /* [in] */ IGaiaCredentialProvider *provider);

+        

+        HRESULT ( STDMETHODCALLTYPE *Terminate )( 

+            IGaiaCredential * This);

+        

+        HRESULT ( STDMETHODCALLTYPE *OnUserAuthenticated )( 

+            IGaiaCredential * This,

+            /* [in] */ BSTR authentication_info,

+            /* [out] */ BSTR *status_text);

+        

+        HRESULT ( STDMETHODCALLTYPE *ReportError )( 

+            IGaiaCredential * This,

+            /* [in] */ LONG status,

+            /* [in] */ LONG substatus,

+            /* [in] */ BSTR status_text);

+        

+        END_INTERFACE

+    } IGaiaCredentialVtbl;

+

+    interface IGaiaCredential

+    {

+        CONST_VTBL struct IGaiaCredentialVtbl *lpVtbl;

+    };

+

+    

+

+#ifdef COBJMACROS

+

+

+#define IGaiaCredential_QueryInterface(This,riid,ppvObject)	\

+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 

+

+#define IGaiaCredential_AddRef(This)	\

+    ( (This)->lpVtbl -> AddRef(This) ) 

+

+#define IGaiaCredential_Release(This)	\

+    ( (This)->lpVtbl -> Release(This) ) 

+

+

+#define IGaiaCredential_Initialize(This,provider)	\

+    ( (This)->lpVtbl -> Initialize(This,provider) ) 

+

+#define IGaiaCredential_Terminate(This)	\

+    ( (This)->lpVtbl -> Terminate(This) ) 

+

+#define IGaiaCredential_OnUserAuthenticated(This,authentication_info,status_text)	\

+    ( (This)->lpVtbl -> OnUserAuthenticated(This,authentication_info,status_text) ) 

+

+#define IGaiaCredential_ReportError(This,status,substatus,status_text)	\

+    ( (This)->lpVtbl -> ReportError(This,status,substatus,status_text) ) 

+

+#endif /* COBJMACROS */

+

+

+#endif 	/* C style interface */

+

+

+

+

+#endif 	/* __IGaiaCredential_INTERFACE_DEFINED__ */

+

+

+#ifndef __IReauthCredential_INTERFACE_DEFINED__

+#define __IReauthCredential_INTERFACE_DEFINED__

+

+/* interface IReauthCredential */

+/* [unique][uuid][object] */ 

+

+

+EXTERN_C const IID IID_IReauthCredential;

+

+#if defined(__cplusplus) && !defined(CINTERFACE)

+    

+    MIDL_INTERFACE("CC75BCEA-A636-4798-BF8E-0FF64D743451")

+    IReauthCredential : public IUnknown

+    {

+    public:

+        virtual HRESULT STDMETHODCALLTYPE SetEmailForReauth( 

+            /* [in] */ BSTR email) = 0;

+        

+        virtual HRESULT STDMETHODCALLTYPE SetOSUserInfo( 

+            /* [in] */ BSTR sid,

+            /* [in] */ BSTR username) = 0;

+        

+    };

+    

+    

+#else 	/* C style interface */

+

+    typedef struct IReauthCredentialVtbl

+    {

+        BEGIN_INTERFACE

+        

+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 

+            IReauthCredential * This,

+            /* [in] */ REFIID riid,

+            /* [annotation][iid_is][out] */ 

+            _COM_Outptr_  void **ppvObject);

+        

+        ULONG ( STDMETHODCALLTYPE *AddRef )( 

+            IReauthCredential * This);

+        

+        ULONG ( STDMETHODCALLTYPE *Release )( 

+            IReauthCredential * This);

+        

+        HRESULT ( STDMETHODCALLTYPE *SetEmailForReauth )( 

+            IReauthCredential * This,

+            /* [in] */ BSTR email);

+        

+        HRESULT ( STDMETHODCALLTYPE *SetOSUserInfo )( 

+            IReauthCredential * This,

+            /* [in] */ BSTR sid,

+            /* [in] */ BSTR username);

+        

+        END_INTERFACE

+    } IReauthCredentialVtbl;

+

+    interface IReauthCredential

+    {

+        CONST_VTBL struct IReauthCredentialVtbl *lpVtbl;

+    };

+

+    

+

+#ifdef COBJMACROS

+

+

+#define IReauthCredential_QueryInterface(This,riid,ppvObject)	\

+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 

+

+#define IReauthCredential_AddRef(This)	\

+    ( (This)->lpVtbl -> AddRef(This) ) 

+

+#define IReauthCredential_Release(This)	\

+    ( (This)->lpVtbl -> Release(This) ) 

+

+

+#define IReauthCredential_SetEmailForReauth(This,email)	\

+    ( (This)->lpVtbl -> SetEmailForReauth(This,email) ) 

+

+#define IReauthCredential_SetOSUserInfo(This,sid,username)	\

+    ( (This)->lpVtbl -> SetOSUserInfo(This,sid,username) ) 

+

+#endif /* COBJMACROS */

+

+

+#endif 	/* C style interface */

+

+

+

+

+#endif 	/* __IReauthCredential_INTERFACE_DEFINED__ */

+

+

+

+#ifndef __GaiaCredentialProviderLib_LIBRARY_DEFINED__

+#define __GaiaCredentialProviderLib_LIBRARY_DEFINED__

+

+/* library GaiaCredentialProviderLib */

+/* [version][uuid] */ 

+

+

+EXTERN_C const IID LIBID_GaiaCredentialProviderLib;

+

+EXTERN_C const CLSID CLSID_GaiaCredentialProvider;

+

+#ifdef __cplusplus

+

+class DECLSPEC_UUID("89adae71-aee5-4ee2-bffb-e8424e06f519")

+GaiaCredentialProvider;

+#endif

+#endif /* __GaiaCredentialProviderLib_LIBRARY_DEFINED__ */

+

+/* Additional Prototypes for ALL interfaces */

+

+unsigned long             __RPC_USER  BSTR_UserSize(     unsigned long *, unsigned long            , BSTR * ); 

+unsigned char * __RPC_USER  BSTR_UserMarshal(  unsigned long *, unsigned char *, BSTR * ); 

+unsigned char * __RPC_USER  BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * ); 

+void                      __RPC_USER  BSTR_UserFree(     unsigned long *, BSTR * ); 

+

+/* end of Additional Prototypes */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif

+

+

diff --git a/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider_p.c b/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider_p.c
new file mode 100644
index 0000000..3cd418d
--- /dev/null
+++ b/third_party/win_build_output/midl/chrome/credential_provider/gaiacp/arm64/gaia_credential_provider_p.c
@@ -0,0 +1,855 @@
+

+

+/* this ALWAYS GENERATED file contains the proxy stub code */

+

+

+ /* File created by MIDL compiler version 8.xx.xxxx */

+/* at a redacted point in time

+ */

+/* Compiler settings for gen/chrome/credential_provider/gaiacp/gaia_credential_provider.idl:

+    Oicf, W1, Zp8, env=Win64 (32b run), target_arch=ARM64 8.01.0622 

+    protocol : dce , ms_ext, c_ext, robust

+    error checks: allocation ref bounds_check enum stub_data 

+    VC __declspec() decoration level: 

+         __declspec(uuid()), __declspec(selectany), __declspec(novtable)

+         DECLSPEC_UUID(), MIDL_INTERFACE()

+*/

+/* @@MIDL_FILE_HEADING(  ) */

+

+#if defined(_M_ARM64)

+

+

+#pragma warning( disable: 4049 )  /* more than 64k source lines */

+#if _MSC_VER >= 1200

+#pragma warning(push)

+#endif

+

+#pragma warning( disable: 4211 )  /* redefine extern to static */

+#pragma warning( disable: 4232 )  /* dllimport identity*/

+#pragma warning( disable: 4024 )  /* array to pointer mapping*/

+#pragma warning( disable: 4152 )  /* function/data pointer conversion in expression */

+

+#define USE_STUBLESS_PROXY

+

+

+/* verify that the <rpcproxy.h> version is high enough to compile this file*/

+#ifndef __REDQ_RPCPROXY_H_VERSION__

+#define __REQUIRED_RPCPROXY_H_VERSION__ 475

+#endif

+

+

+#include "rpcproxy.h"

+#ifndef __RPCPROXY_H_VERSION__

+#error this stub requires an updated version of <rpcproxy.h>

+#endif /* __RPCPROXY_H_VERSION__ */

+

+

+#include "gaia_credential_provider_i.h"

+

+#define TYPE_FORMAT_STRING_SIZE   93                                

+#define PROC_FORMAT_STRING_SIZE   383                               

+#define EXPR_FORMAT_STRING_SIZE   1                                 

+#define TRANSMIT_AS_TABLE_SIZE    0            

+#define WIRE_MARSHAL_TABLE_SIZE   1            

+

+typedef struct _gaia_credential_provider_MIDL_TYPE_FORMAT_STRING

+    {

+    short          Pad;

+    unsigned char  Format[ TYPE_FORMAT_STRING_SIZE ];

+    } gaia_credential_provider_MIDL_TYPE_FORMAT_STRING;

+

+typedef struct _gaia_credential_provider_MIDL_PROC_FORMAT_STRING

+    {

+    short          Pad;

+    unsigned char  Format[ PROC_FORMAT_STRING_SIZE ];

+    } gaia_credential_provider_MIDL_PROC_FORMAT_STRING;

+

+typedef struct _gaia_credential_provider_MIDL_EXPR_FORMAT_STRING

+    {

+    long          Pad;

+    unsigned char  Format[ EXPR_FORMAT_STRING_SIZE ];

+    } gaia_credential_provider_MIDL_EXPR_FORMAT_STRING;

+

+

+static const RPC_SYNTAX_IDENTIFIER  _RpcTransferSyntax = 

+{{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}};

+

+

+extern const gaia_credential_provider_MIDL_TYPE_FORMAT_STRING gaia_credential_provider__MIDL_TypeFormatString;

+extern const gaia_credential_provider_MIDL_PROC_FORMAT_STRING gaia_credential_provider__MIDL_ProcFormatString;

+extern const gaia_credential_provider_MIDL_EXPR_FORMAT_STRING gaia_credential_provider__MIDL_ExprFormatString;

+

+

+extern const MIDL_STUB_DESC Object_StubDesc;

+

+

+extern const MIDL_SERVER_INFO IGaiaCredentialProvider_ServerInfo;

+extern const MIDL_STUBLESS_PROXY_INFO IGaiaCredentialProvider_ProxyInfo;

+

+

+extern const MIDL_STUB_DESC Object_StubDesc;

+

+

+extern const MIDL_SERVER_INFO IGaiaCredentialProviderForTesting_ServerInfo;

+extern const MIDL_STUBLESS_PROXY_INFO IGaiaCredentialProviderForTesting_ProxyInfo;

+

+

+extern const MIDL_STUB_DESC Object_StubDesc;

+

+

+extern const MIDL_SERVER_INFO IGaiaCredential_ServerInfo;

+extern const MIDL_STUBLESS_PROXY_INFO IGaiaCredential_ProxyInfo;

+

+

+extern const MIDL_STUB_DESC Object_StubDesc;

+

+

+extern const MIDL_SERVER_INFO IReauthCredential_ServerInfo;

+extern const MIDL_STUBLESS_PROXY_INFO IReauthCredential_ProxyInfo;

+

+

+extern const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[ WIRE_MARSHAL_TABLE_SIZE ];

+

+#if !defined(__RPC_ARM64__)

+#error  Invalid build platform for this stub.

+#endif

+

+static const gaia_credential_provider_MIDL_PROC_FORMAT_STRING gaia_credential_provider__MIDL_ProcFormatString =

+    {

+        0,

+        {

+

+	/* Procedure OnUserAuthenticated */

+

+			0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/*  2 */	NdrFcLong( 0x0 ),	/* 0 */

+/*  6 */	NdrFcShort( 0x3 ),	/* 3 */

+/*  8 */	NdrFcShort( 0x38 ),	/* ARM64 Stack size/offset = 56 */

+/* 10 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 12 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 14 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+			0x6,		/* 6 */

+/* 16 */	0x12,		/* 18 */

+			0x5,		/* Ext Flags:  new corr desc, srv corr check, */

+/* 18 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 20 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 22 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 24 */	NdrFcShort( 0x6 ),	/* 6 */

+/* 26 */	0x6,		/* 6 */

+			0x80,		/* 128 */

+/* 28 */	0x81,		/* 129 */

+			0x82,		/* 130 */

+/* 30 */	0x83,		/* 131 */

+			0x84,		/* 132 */

+/* 32 */	0x85,		/* 133 */

+			0x0,		/* 0 */

+

+	/* Parameter credential */

+

+/* 34 */	NdrFcShort( 0xb ),	/* Flags:  must size, must free, in, */

+/* 36 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 38 */	NdrFcShort( 0x2 ),	/* Type Offset=2 */

+

+	/* Parameter username */

+

+/* 40 */	NdrFcShort( 0x8b ),	/* Flags:  must size, must free, in, by val, */

+/* 42 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 44 */	NdrFcShort( 0x2e ),	/* Type Offset=46 */

+

+	/* Parameter password */

+

+/* 46 */	NdrFcShort( 0x8b ),	/* Flags:  must size, must free, in, by val, */

+/* 48 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 50 */	NdrFcShort( 0x2e ),	/* Type Offset=46 */

+

+	/* Parameter sid */

+

+/* 52 */	NdrFcShort( 0x8b ),	/* Flags:  must size, must free, in, by val, */

+/* 54 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

+/* 56 */	NdrFcShort( 0x2e ),	/* Type Offset=46 */

+

+	/* Parameter fire_credentials_changed */

+

+/* 58 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 60 */	NdrFcShort( 0x28 ),	/* ARM64 Stack size/offset = 40 */

+/* 62 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Return value */

+

+/* 64 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 66 */	NdrFcShort( 0x30 ),	/* ARM64 Stack size/offset = 48 */

+/* 68 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure Terminate */

+

+

+	/* Procedure HasInternetConnection */

+

+/* 70 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 72 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 76 */	NdrFcShort( 0x4 ),	/* 4 */

+/* 78 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 80 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 82 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 84 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+			0x1,		/* 1 */

+/* 86 */	0xc,		/* 12 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 88 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 90 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 92 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 94 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 96 */	0x1,		/* 1 */

+			0x80,		/* 128 */

+

+	/* Return value */

+

+

+	/* Return value */

+

+/* 98 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 100 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 102 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure SetHasInternetConnection */

+

+/* 104 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 106 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 110 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 112 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 114 */	NdrFcShort( 0x6 ),	/* 6 */

+/* 116 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 118 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+			0x2,		/* 2 */

+/* 120 */	0xe,		/* 14 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 122 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 124 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 126 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 128 */	NdrFcShort( 0x2 ),	/* 2 */

+/* 130 */	0x2,		/* 2 */

+			0x80,		/* 128 */

+/* 132 */	0x81,		/* 129 */

+			0x0,		/* 0 */

+

+	/* Parameter hic */

+

+/* 134 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 136 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 138 */	0xd,		/* FC_ENUM16 */

+			0x0,		/* 0 */

+

+	/* Return value */

+

+/* 140 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 142 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 144 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure Initialize */

+

+/* 146 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 148 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 152 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 154 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 156 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 158 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 160 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+			0x2,		/* 2 */

+/* 162 */	0xe,		/* 14 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 164 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 166 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 168 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 170 */	NdrFcShort( 0x2 ),	/* 2 */

+/* 172 */	0x2,		/* 2 */

+			0x80,		/* 128 */

+/* 174 */	0x81,		/* 129 */

+			0x0,		/* 0 */

+

+	/* Parameter provider */

+

+/* 176 */	NdrFcShort( 0xb ),	/* Flags:  must size, must free, in, */

+/* 178 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 180 */	NdrFcShort( 0x38 ),	/* Type Offset=56 */

+

+	/* Return value */

+

+/* 182 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 184 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 186 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure OnUserAuthenticated */

+

+/* 188 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 190 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 194 */	NdrFcShort( 0x5 ),	/* 5 */

+/* 196 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

+/* 198 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 200 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 202 */	0x47,		/* Oi2 Flags:  srv must size, clt must size, has return, has ext, */

+			0x3,		/* 3 */

+/* 204 */	0xe,		/* 14 */

+			0x7,		/* Ext Flags:  new corr desc, clt corr check, srv corr check, */

+/* 206 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 208 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 210 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 212 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 214 */	0x3,		/* 3 */

+			0x80,		/* 128 */

+/* 216 */	0x81,		/* 129 */

+			0x82,		/* 130 */

+

+	/* Parameter authentication_info */

+

+/* 218 */	NdrFcShort( 0x8b ),	/* Flags:  must size, must free, in, by val, */

+/* 220 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 222 */	NdrFcShort( 0x2e ),	/* Type Offset=46 */

+

+	/* Parameter status_text */

+

+/* 224 */	NdrFcShort( 0x2113 ),	/* Flags:  must size, must free, out, simple ref, srv alloc size=8 */

+/* 226 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 228 */	NdrFcShort( 0x52 ),	/* Type Offset=82 */

+

+	/* Return value */

+

+/* 230 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 232 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 234 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure ReportError */

+

+/* 236 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 238 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 242 */	NdrFcShort( 0x6 ),	/* 6 */

+/* 244 */	NdrFcShort( 0x28 ),	/* ARM64 Stack size/offset = 40 */

+/* 246 */	NdrFcShort( 0x10 ),	/* 16 */

+/* 248 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 250 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+			0x4,		/* 4 */

+/* 252 */	0x10,		/* 16 */

+			0x5,		/* Ext Flags:  new corr desc, srv corr check, */

+/* 254 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 256 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 258 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 260 */	NdrFcShort( 0x4 ),	/* 4 */

+/* 262 */	0x4,		/* 4 */

+			0x80,		/* 128 */

+/* 264 */	0x81,		/* 129 */

+			0x82,		/* 130 */

+/* 266 */	0x83,		/* 131 */

+			0x0,		/* 0 */

+

+	/* Parameter status */

+

+/* 268 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 270 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 272 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter substatus */

+

+/* 274 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 276 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 278 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter status_text */

+

+/* 280 */	NdrFcShort( 0x8b ),	/* Flags:  must size, must free, in, by val, */

+/* 282 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 284 */	NdrFcShort( 0x2e ),	/* Type Offset=46 */

+

+	/* Return value */

+

+/* 286 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 288 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

+/* 290 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure SetEmailForReauth */

+

+/* 292 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 294 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 298 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 300 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 302 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 304 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 306 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+			0x2,		/* 2 */

+/* 308 */	0xe,		/* 14 */

+			0x5,		/* Ext Flags:  new corr desc, srv corr check, */

+/* 310 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 312 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 314 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 316 */	NdrFcShort( 0x2 ),	/* 2 */

+/* 318 */	0x2,		/* 2 */

+			0x80,		/* 128 */

+/* 320 */	0x81,		/* 129 */

+			0x0,		/* 0 */

+

+	/* Parameter email */

+

+/* 322 */	NdrFcShort( 0x8b ),	/* Flags:  must size, must free, in, by val, */

+/* 324 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 326 */	NdrFcShort( 0x2e ),	/* Type Offset=46 */

+

+	/* Return value */

+

+/* 328 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 330 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 332 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure SetOSUserInfo */

+

+/* 334 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 336 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 340 */	NdrFcShort( 0x4 ),	/* 4 */

+/* 342 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

+/* 344 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 346 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 348 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+			0x3,		/* 3 */

+/* 350 */	0xe,		/* 14 */

+			0x5,		/* Ext Flags:  new corr desc, srv corr check, */

+/* 352 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 354 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 356 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 358 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 360 */	0x3,		/* 3 */

+			0x80,		/* 128 */

+/* 362 */	0x81,		/* 129 */

+			0x82,		/* 130 */

+

+	/* Parameter sid */

+

+/* 364 */	NdrFcShort( 0x8b ),	/* Flags:  must size, must free, in, by val, */

+/* 366 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 368 */	NdrFcShort( 0x2e ),	/* Type Offset=46 */

+

+	/* Parameter username */

+

+/* 370 */	NdrFcShort( 0x8b ),	/* Flags:  must size, must free, in, by val, */

+/* 372 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 374 */	NdrFcShort( 0x2e ),	/* Type Offset=46 */

+

+	/* Return value */

+

+/* 376 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 378 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 380 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+			0x0

+        }

+    };

+

+static const gaia_credential_provider_MIDL_TYPE_FORMAT_STRING gaia_credential_provider__MIDL_TypeFormatString =

+    {

+        0,

+        {

+			NdrFcShort( 0x0 ),	/* 0 */

+/*  2 */	

+			0x2f,		/* FC_IP */

+			0x5a,		/* FC_CONSTANT_IID */

+/*  4 */	NdrFcLong( 0x0 ),	/* 0 */

+/*  8 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 10 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 12 */	0xc0,		/* 192 */

+			0x0,		/* 0 */

+/* 14 */	0x0,		/* 0 */

+			0x0,		/* 0 */

+/* 16 */	0x0,		/* 0 */

+			0x0,		/* 0 */

+/* 18 */	0x0,		/* 0 */

+			0x46,		/* 70 */

+/* 20 */	

+			0x12, 0x0,	/* FC_UP */

+/* 22 */	NdrFcShort( 0xe ),	/* Offset= 14 (36) */

+/* 24 */	

+			0x1b,		/* FC_CARRAY */

+			0x1,		/* 1 */

+/* 26 */	NdrFcShort( 0x2 ),	/* 2 */

+/* 28 */	0x9,		/* Corr desc: FC_ULONG */

+			0x0,		/*  */

+/* 30 */	NdrFcShort( 0xfffc ),	/* -4 */

+/* 32 */	NdrFcShort( 0x1 ),	/* Corr flags:  early, */

+/* 34 */	0x6,		/* FC_SHORT */

+			0x5b,		/* FC_END */

+/* 36 */	

+			0x17,		/* FC_CSTRUCT */

+			0x3,		/* 3 */

+/* 38 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 40 */	NdrFcShort( 0xfff0 ),	/* Offset= -16 (24) */

+/* 42 */	0x8,		/* FC_LONG */

+			0x8,		/* FC_LONG */

+/* 44 */	0x5c,		/* FC_PAD */

+			0x5b,		/* FC_END */

+/* 46 */	0xb4,		/* FC_USER_MARSHAL */

+			0x83,		/* 131 */

+/* 48 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 50 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 52 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 54 */	NdrFcShort( 0xffde ),	/* Offset= -34 (20) */

+/* 56 */	

+			0x2f,		/* FC_IP */

+			0x5a,		/* FC_CONSTANT_IID */

+/* 58 */	NdrFcLong( 0xcec9ef6c ),	/* -825626772 */

+/* 62 */	NdrFcShort( 0xb2e6 ),	/* -19738 */

+/* 64 */	NdrFcShort( 0x4bb6 ),	/* 19382 */

+/* 66 */	0x8f,		/* 143 */

+			0x1e,		/* 30 */

+/* 68 */	0x17,		/* 23 */

+			0x47,		/* 71 */

+/* 70 */	0xba,		/* 186 */

+			0x4f,		/* 79 */

+/* 72 */	0x71,		/* 113 */

+			0x38,		/* 56 */

+/* 74 */	

+			0x11, 0x4,	/* FC_RP [alloced_on_stack] */

+/* 76 */	NdrFcShort( 0x6 ),	/* Offset= 6 (82) */

+/* 78 */	

+			0x13, 0x0,	/* FC_OP */

+/* 80 */	NdrFcShort( 0xffd4 ),	/* Offset= -44 (36) */

+/* 82 */	0xb4,		/* FC_USER_MARSHAL */

+			0x83,		/* 131 */

+/* 84 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 86 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 88 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 90 */	NdrFcShort( 0xfff4 ),	/* Offset= -12 (78) */

+

+			0x0

+        }

+    };

+

+static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[ WIRE_MARSHAL_TABLE_SIZE ] = 

+        {

+            

+            {

+            BSTR_UserSize

+            ,BSTR_UserMarshal

+            ,BSTR_UserUnmarshal

+            ,BSTR_UserFree

+            }

+

+        };

+

+

+

+/* Object interface: IUnknown, ver. 0.0,

+   GUID={0x00000000,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */

+

+

+/* Object interface: IGaiaCredentialProvider, ver. 0.0,

+   GUID={0xCEC9EF6C,0xB2E6,0x4BB6,{0x8F,0x1E,0x17,0x47,0xBA,0x4F,0x71,0x38}} */

+

+#pragma code_seg(".orpc")

+static const unsigned short IGaiaCredentialProvider_FormatStringOffsetTable[] =

+    {

+    0,

+    70

+    };

+

+static const MIDL_STUBLESS_PROXY_INFO IGaiaCredentialProvider_ProxyInfo =

+    {

+    &Object_StubDesc,

+    gaia_credential_provider__MIDL_ProcFormatString.Format,

+    &IGaiaCredentialProvider_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0

+    };

+

+

+static const MIDL_SERVER_INFO IGaiaCredentialProvider_ServerInfo = 

+    {

+    &Object_StubDesc,

+    0,

+    gaia_credential_provider__MIDL_ProcFormatString.Format,

+    &IGaiaCredentialProvider_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0,

+    0};

+CINTERFACE_PROXY_VTABLE(5) _IGaiaCredentialProviderProxyVtbl = 

+{

+    &IGaiaCredentialProvider_ProxyInfo,

+    &IID_IGaiaCredentialProvider,

+    IUnknown_QueryInterface_Proxy,

+    IUnknown_AddRef_Proxy,

+    IUnknown_Release_Proxy ,

+    (void *) (INT_PTR) -1 /* IGaiaCredentialProvider::OnUserAuthenticated */ ,

+    (void *) (INT_PTR) -1 /* IGaiaCredentialProvider::HasInternetConnection */

+};

+

+const CInterfaceStubVtbl _IGaiaCredentialProviderStubVtbl =

+{

+    &IID_IGaiaCredentialProvider,

+    &IGaiaCredentialProvider_ServerInfo,

+    5,

+    0, /* pure interpreted */

+    CStdStubBuffer_METHODS

+};

+

+

+/* Standard interface: __MIDL_itf_gaia_credential_provider_0000_0001, ver. 0.0,

+   GUID={0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} */

+

+

+/* Object interface: IGaiaCredentialProviderForTesting, ver. 0.0,

+   GUID={0x224CE2FB,0x2977,0x4585,{0xBD,0x46,0x1B,0xAE,0x8D,0x79,0x64,0xDE}} */

+

+#pragma code_seg(".orpc")

+static const unsigned short IGaiaCredentialProviderForTesting_FormatStringOffsetTable[] =

+    {

+    104

+    };

+

+static const MIDL_STUBLESS_PROXY_INFO IGaiaCredentialProviderForTesting_ProxyInfo =

+    {

+    &Object_StubDesc,

+    gaia_credential_provider__MIDL_ProcFormatString.Format,

+    &IGaiaCredentialProviderForTesting_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0

+    };

+

+

+static const MIDL_SERVER_INFO IGaiaCredentialProviderForTesting_ServerInfo = 

+    {

+    &Object_StubDesc,

+    0,

+    gaia_credential_provider__MIDL_ProcFormatString.Format,

+    &IGaiaCredentialProviderForTesting_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0,

+    0};

+CINTERFACE_PROXY_VTABLE(4) _IGaiaCredentialProviderForTestingProxyVtbl = 

+{

+    &IGaiaCredentialProviderForTesting_ProxyInfo,

+    &IID_IGaiaCredentialProviderForTesting,

+    IUnknown_QueryInterface_Proxy,

+    IUnknown_AddRef_Proxy,

+    IUnknown_Release_Proxy ,

+    (void *) (INT_PTR) -1 /* IGaiaCredentialProviderForTesting::SetHasInternetConnection */

+};

+

+const CInterfaceStubVtbl _IGaiaCredentialProviderForTestingStubVtbl =

+{

+    &IID_IGaiaCredentialProviderForTesting,

+    &IGaiaCredentialProviderForTesting_ServerInfo,

+    4,

+    0, /* pure interpreted */

+    CStdStubBuffer_METHODS

+};

+

+

+/* Object interface: IGaiaCredential, ver. 0.0,

+   GUID={0xE5BF88DF,0x9966,0x465B,{0xB2,0x33,0xC1,0xCA,0xC7,0x51,0x0A,0x59}} */

+

+#pragma code_seg(".orpc")

+static const unsigned short IGaiaCredential_FormatStringOffsetTable[] =

+    {

+    146,

+    70,

+    188,

+    236

+    };

+

+static const MIDL_STUBLESS_PROXY_INFO IGaiaCredential_ProxyInfo =

+    {

+    &Object_StubDesc,

+    gaia_credential_provider__MIDL_ProcFormatString.Format,

+    &IGaiaCredential_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0

+    };

+

+

+static const MIDL_SERVER_INFO IGaiaCredential_ServerInfo = 

+    {

+    &Object_StubDesc,

+    0,

+    gaia_credential_provider__MIDL_ProcFormatString.Format,

+    &IGaiaCredential_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0,

+    0};

+CINTERFACE_PROXY_VTABLE(7) _IGaiaCredentialProxyVtbl = 

+{

+    &IGaiaCredential_ProxyInfo,

+    &IID_IGaiaCredential,

+    IUnknown_QueryInterface_Proxy,

+    IUnknown_AddRef_Proxy,

+    IUnknown_Release_Proxy ,

+    (void *) (INT_PTR) -1 /* IGaiaCredential::Initialize */ ,

+    (void *) (INT_PTR) -1 /* IGaiaCredential::Terminate */ ,

+    (void *) (INT_PTR) -1 /* IGaiaCredential::OnUserAuthenticated */ ,

+    (void *) (INT_PTR) -1 /* IGaiaCredential::ReportError */

+};

+

+const CInterfaceStubVtbl _IGaiaCredentialStubVtbl =

+{

+    &IID_IGaiaCredential,

+    &IGaiaCredential_ServerInfo,

+    7,

+    0, /* pure interpreted */

+    CStdStubBuffer_METHODS

+};

+

+

+/* Object interface: IReauthCredential, ver. 0.0,

+   GUID={0xCC75BCEA,0xA636,0x4798,{0xBF,0x8E,0x0F,0xF6,0x4D,0x74,0x34,0x51}} */

+

+#pragma code_seg(".orpc")

+static const unsigned short IReauthCredential_FormatStringOffsetTable[] =

+    {

+    292,

+    334

+    };

+

+static const MIDL_STUBLESS_PROXY_INFO IReauthCredential_ProxyInfo =

+    {

+    &Object_StubDesc,

+    gaia_credential_provider__MIDL_ProcFormatString.Format,

+    &IReauthCredential_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0

+    };

+

+

+static const MIDL_SERVER_INFO IReauthCredential_ServerInfo = 

+    {

+    &Object_StubDesc,

+    0,

+    gaia_credential_provider__MIDL_ProcFormatString.Format,

+    &IReauthCredential_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0,

+    0};

+CINTERFACE_PROXY_VTABLE(5) _IReauthCredentialProxyVtbl = 

+{

+    &IReauthCredential_ProxyInfo,

+    &IID_IReauthCredential,

+    IUnknown_QueryInterface_Proxy,

+    IUnknown_AddRef_Proxy,

+    IUnknown_Release_Proxy ,

+    (void *) (INT_PTR) -1 /* IReauthCredential::SetEmailForReauth */ ,

+    (void *) (INT_PTR) -1 /* IReauthCredential::SetOSUserInfo */

+};

+

+const CInterfaceStubVtbl _IReauthCredentialStubVtbl =

+{

+    &IID_IReauthCredential,

+    &IReauthCredential_ServerInfo,

+    5,

+    0, /* pure interpreted */

+    CStdStubBuffer_METHODS

+};

+

+static const MIDL_STUB_DESC Object_StubDesc = 

+    {

+    0,

+    NdrOleAllocate,

+    NdrOleFree,

+    0,

+    0,

+    0,

+    0,

+    0,

+    gaia_credential_provider__MIDL_TypeFormatString.Format,

+    1, /* -error bounds_check flag */

+    0x50002, /* Ndr library version */

+    0,

+    0x801026e, /* MIDL Version 8.1.622 */

+    0,

+    UserMarshalRoutines,

+    0,  /* notify & notify_flag routine table */

+    0x1, /* MIDL flag */

+    0, /* cs routines */

+    0,   /* proxy/server info */

+    0

+    };

+

+const CInterfaceProxyVtbl * const _gaia_credential_provider_ProxyVtblList[] = 

+{

+    ( CInterfaceProxyVtbl *) &_IGaiaCredentialProviderProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IGaiaCredentialProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IReauthCredentialProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IGaiaCredentialProviderForTestingProxyVtbl,

+    0

+};

+

+const CInterfaceStubVtbl * const _gaia_credential_provider_StubVtblList[] = 

+{

+    ( CInterfaceStubVtbl *) &_IGaiaCredentialProviderStubVtbl,

+    ( CInterfaceStubVtbl *) &_IGaiaCredentialStubVtbl,

+    ( CInterfaceStubVtbl *) &_IReauthCredentialStubVtbl,

+    ( CInterfaceStubVtbl *) &_IGaiaCredentialProviderForTestingStubVtbl,

+    0

+};

+

+PCInterfaceName const _gaia_credential_provider_InterfaceNamesList[] = 

+{

+    "IGaiaCredentialProvider",

+    "IGaiaCredential",

+    "IReauthCredential",

+    "IGaiaCredentialProviderForTesting",

+    0

+};

+

+

+#define _gaia_credential_provider_CHECK_IID(n)	IID_GENERIC_CHECK_IID( _gaia_credential_provider, pIID, n)

+

+int __stdcall _gaia_credential_provider_IID_Lookup( const IID * pIID, int * pIndex )

+{

+    IID_BS_LOOKUP_SETUP

+

+    IID_BS_LOOKUP_INITIAL_TEST( _gaia_credential_provider, 4, 2 )

+    IID_BS_LOOKUP_NEXT_TEST( _gaia_credential_provider, 1 )

+    IID_BS_LOOKUP_RETURN_RESULT( _gaia_credential_provider, 4, *pIndex )

+    

+}

+

+const ExtendedProxyFileInfo gaia_credential_provider_ProxyFileInfo = 

+{

+    (PCInterfaceProxyVtblList *) & _gaia_credential_provider_ProxyVtblList,

+    (PCInterfaceStubVtblList *) & _gaia_credential_provider_StubVtblList,

+    (const PCInterfaceName * ) & _gaia_credential_provider_InterfaceNamesList,

+    0, /* no delegation */

+    & _gaia_credential_provider_IID_Lookup, 

+    4,

+    2,

+    0, /* table of [async_uuid] interfaces */

+    0, /* Filler1 */

+    0, /* Filler2 */

+    0  /* Filler3 */

+};

+#if _MSC_VER >= 1200

+#pragma warning(pop)

+#endif

+

+

+#endif /* defined(_M_ARM64)*/

+

diff --git a/third_party/win_build_output/midl/google_update/arm64/google_update_idl.h b/third_party/win_build_output/midl/google_update/arm64/google_update_idl.h
index 719f6d6..14d6f8b1 100644
--- a/third_party/win_build_output/midl/google_update/arm64/google_update_idl.h
+++ b/third_party/win_build_output/midl/google_update/arm64/google_update_idl.h
@@ -199,6 +199,13 @@
 #endif 	/* __IProcessLauncher2_FWD_DEFINED__ */

 

 

+#ifndef __IOneClickProcessLauncher_FWD_DEFINED__

+#define __IOneClickProcessLauncher_FWD_DEFINED__

+typedef interface IOneClickProcessLauncher IOneClickProcessLauncher;

+

+#endif 	/* __IOneClickProcessLauncher_FWD_DEFINED__ */

+

+

 #ifndef __IProgressWndEvents_FWD_DEFINED__

 #define __IProgressWndEvents_FWD_DEFINED__

 typedef interface IProgressWndEvents IProgressWndEvents;

@@ -483,6 +490,30 @@
 #endif 	/* __ProcessLauncherClass_FWD_DEFINED__ */

 

 

+#ifndef __OneClickUserProcessLauncherClass_FWD_DEFINED__

+#define __OneClickUserProcessLauncherClass_FWD_DEFINED__

+

+#ifdef __cplusplus

+typedef class OneClickUserProcessLauncherClass OneClickUserProcessLauncherClass;

+#else

+typedef struct OneClickUserProcessLauncherClass OneClickUserProcessLauncherClass;

+#endif /* __cplusplus */

+

+#endif 	/* __OneClickUserProcessLauncherClass_FWD_DEFINED__ */

+

+

+#ifndef __OneClickMachineProcessLauncherClass_FWD_DEFINED__

+#define __OneClickMachineProcessLauncherClass_FWD_DEFINED__

+

+#ifdef __cplusplus

+typedef class OneClickMachineProcessLauncherClass OneClickMachineProcessLauncherClass;

+#else

+typedef struct OneClickMachineProcessLauncherClass OneClickMachineProcessLauncherClass;

+#endif /* __cplusplus */

+

+#endif 	/* __OneClickMachineProcessLauncherClass_FWD_DEFINED__ */

+

+

 #ifndef __OnDemandUserAppsClass_FWD_DEFINED__

 #define __OnDemandUserAppsClass_FWD_DEFINED__

 

@@ -642,7 +673,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("ddd4b5d4-fd54-497c-8789-0830f29a60ee")

+    MIDL_INTERFACE("6DB17455-4E85-46e7-9D23-E555E4B005AF")

     IGoogleUpdate3 : public IDispatch

     {

     public:

@@ -794,7 +825,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("ab4f4a7e-977c-4e23-ad8f-626a491715df")

+    MIDL_INTERFACE("fe908cdd-22bb-472a-9870-1a0390e42f36")

     IAppBundle : public IDispatch

     {

     public:

@@ -1248,7 +1279,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("195a2eb3-21ee-43ca-9f23-93c2c9934e2e")

+    MIDL_INTERFACE("76F7B787-A67C-4c73-82C7-31F5E3AABC5C")

     IApp : public IDispatch

     {

     public:

@@ -1710,7 +1741,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("c06ee550-7248-488e-971e-b60c0ab3a6e4")

+    MIDL_INTERFACE("084D78A8-B084-4E14-A629-A2C419B0E3D9")

     IApp2 : public IApp

     {

     public:

@@ -2090,7 +2121,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("5f9c80b5-9e50-43c9-887c-7c6412e110df")

+    MIDL_INTERFACE("4DE778FE-F195-4ee3-9DAB-FE446C239221")

     IAppCommand : public IDispatch

     {

     public:

@@ -2266,7 +2297,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("7e29be61-5809-443f-9b5d-cf22156694eb")

+    MIDL_INTERFACE("3D05F64F-71E3-48A5-BF6B-83315BC8AE1F")

     IAppCommand2 : public IAppCommand

     {

     public:

@@ -2433,7 +2464,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("7b3b7a69-7d88-4847-a6bc-90e246a41f69")

+    MIDL_INTERFACE("BCDCB538-01C0-46d1-A6A7-52F4D021C272")

     IAppVersion : public IDispatch

     {

     public:

@@ -2585,7 +2616,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("c853632e-36ca-4999-b992-ec0d408cf5ab")

+    MIDL_INTERFACE("DCAB8386-4F03-4dbd-A366-D90BC9F68DE6")

     IPackage : public IDispatch

     {

     public:

@@ -2735,7 +2766,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("177cae89-4ad6-42f4-a458-00ec3389e3fe")

+    MIDL_INTERFACE("247954F9-9EDC-4E68-8CC3-150C2B89EADF")

     ICurrentState : public IDispatch

     {

     public:

@@ -3025,7 +3056,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("3e102dc6-1edb-46a1-8488-61f71b35ed5f")

+    MIDL_INTERFACE("4E223325-C16B-4eeb-AEDC-19AA99A237FA")

     IRegistrationUpdateHook : public IDispatch

     {

     public:

@@ -3157,7 +3188,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("2603c88b-f971-4167-9de1-871ee4a3dc84")

+    MIDL_INTERFACE("b3a47570-0a85-4aea-8270-529d47899603")

     ICredentialDialog : public IUnknown

     {

     public:

@@ -3245,7 +3276,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("6dffe7fe-3153-4af1-95d8-f8fcca97e56b")

+    MIDL_INTERFACE("494B20CF-282E-4BDD-9F5D-B70CB09D351E")

     IGoogleUpdate3Web : public IDispatch

     {

     public:

@@ -3375,7 +3406,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("1b9063e4-3882-485e-8797-f28a0240782f")

+    MIDL_INTERFACE("2D363682-561D-4c3a-81C6-F2F82107562A")

     IGoogleUpdate3WebSecurity : public IUnknown

     {

     public:

@@ -3455,7 +3486,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("837e40da-eb1b-440c-8623-0f14df158dc0")

+    MIDL_INTERFACE("DD42475D-6D46-496a-924E-BD5630B4CBBA")

     IAppBundleWeb : public IDispatch

     {

     public:

@@ -3739,7 +3770,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("3a49f783-1c7d-4d35-8f63-5c1c206b9b6e")

+    MIDL_INTERFACE("18D0F672-18B4-48e6-AD36-6E6BF01DBBC4")

     IAppWeb : public IDispatch

     {

     public:

@@ -3955,7 +3986,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("2ec826cb-5478-4533-9015-7580b3b5e03a")

+    MIDL_INTERFACE("8476CE12-AE1F-4198-805C-BA0F9B783F57")

     IAppCommandWeb : public IDispatch

     {

     public:

@@ -4131,7 +4162,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("450cf5ff-95c4-4679-beca-22680389ecb9")

+    MIDL_INTERFACE("0CD01D1E-4A1C-489d-93B9-9B6672877C57")

     IAppVersionWeb : public IDispatch

     {

     public:

@@ -4283,7 +4314,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("9a6b447a-35e2-4f6b-a87b-5deebbfdad17")

+    MIDL_INTERFACE("2E629606-312A-482f-9B12-2C4ABF6F0B6D")

     ICoCreateAsyncStatus : public IDispatch

     {

     public:

@@ -4433,7 +4464,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("c20433b3-0d4b-49f6-9b6c-6ee0fae07837")

+    MIDL_INTERFACE("DAB1D343-1B2A-47f9-B445-93DC50704BFE")

     ICoCreateAsync : public IUnknown

     {

     public:

@@ -4517,7 +4548,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("e4518371-7326-4865-87f8-d9d3f3b287a3")

+    MIDL_INTERFACE("5B25A8DC-1780-4178-A629-6BE8B8DEFAA2")

     IBrowserHttpRequest2 : public IUnknown

     {

     public:

@@ -4609,7 +4640,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("a5135e58-384f-4244-9a5f-30fa9259413c")

+    MIDL_INTERFACE("128C2DA6-2BC0-44c0-B3F6-4EC22E647964")

     IProcessLauncher : public IUnknown

     {

     public:

@@ -4717,7 +4748,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("a6556dff-ab15-4dc3-a890-ab54120beaec")

+    MIDL_INTERFACE("D106AB5F-A70E-400E-A21B-96208C1D8DBB")

     IProcessLauncher2 : public IProcessLauncher

     {

     public:

@@ -4818,11 +4849,93 @@
 #endif 	/* __IProcessLauncher2_INTERFACE_DEFINED__ */

 

 

-/* interface __MIDL_itf_google_update_idl_0000_0022 */

+#ifndef __IOneClickProcessLauncher_INTERFACE_DEFINED__

+#define __IOneClickProcessLauncher_INTERFACE_DEFINED__

+

+/* interface IOneClickProcessLauncher */

+/* [unique][helpstring][uuid][oleautomation][object] */ 

+

+

+EXTERN_C const IID IID_IOneClickProcessLauncher;

+

+#if defined(__cplusplus) && !defined(CINTERFACE)

+    

+    MIDL_INTERFACE("5CCCB0EF-7073-4516-8028-4C628D0C8AAB")

+    IOneClickProcessLauncher : public IUnknown

+    {

+    public:

+        virtual HRESULT STDMETHODCALLTYPE LaunchAppCommand( 

+            /* [string][in] */ const WCHAR *app_guid,

+            /* [string][in] */ const WCHAR *cmd_id) = 0;

+        

+    };

+    

+    

+#else 	/* C style interface */

+

+    typedef struct IOneClickProcessLauncherVtbl

+    {

+        BEGIN_INTERFACE

+        

+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 

+            IOneClickProcessLauncher * This,

+            /* [in] */ REFIID riid,

+            /* [annotation][iid_is][out] */ 

+            _COM_Outptr_  void **ppvObject);

+        

+        ULONG ( STDMETHODCALLTYPE *AddRef )( 

+            IOneClickProcessLauncher * This);

+        

+        ULONG ( STDMETHODCALLTYPE *Release )( 

+            IOneClickProcessLauncher * This);

+        

+        HRESULT ( STDMETHODCALLTYPE *LaunchAppCommand )( 

+            IOneClickProcessLauncher * This,

+            /* [string][in] */ const WCHAR *app_guid,

+            /* [string][in] */ const WCHAR *cmd_id);

+        

+        END_INTERFACE

+    } IOneClickProcessLauncherVtbl;

+

+    interface IOneClickProcessLauncher

+    {

+        CONST_VTBL struct IOneClickProcessLauncherVtbl *lpVtbl;

+    };

+

+    

+

+#ifdef COBJMACROS

+

+

+#define IOneClickProcessLauncher_QueryInterface(This,riid,ppvObject)	\

+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 

+

+#define IOneClickProcessLauncher_AddRef(This)	\

+    ( (This)->lpVtbl -> AddRef(This) ) 

+

+#define IOneClickProcessLauncher_Release(This)	\

+    ( (This)->lpVtbl -> Release(This) ) 

+

+

+#define IOneClickProcessLauncher_LaunchAppCommand(This,app_guid,cmd_id)	\

+    ( (This)->lpVtbl -> LaunchAppCommand(This,app_guid,cmd_id) ) 

+

+#endif /* COBJMACROS */

+

+

+#endif 	/* C style interface */

+

+

+

+

+#endif 	/* __IOneClickProcessLauncher_INTERFACE_DEFINED__ */

+

+

+/* interface __MIDL_itf_google_update_idl_0000_0023 */

 /* [local] */ 

 

 typedef /* [public][public] */ 

-enum __MIDL___MIDL_itf_google_update_idl_0000_0022_0001

+enum __MIDL___MIDL_itf_google_update_idl_0000_0023_0001

     {

         COMPLETION_CODE_SUCCESS	= 1,

         COMPLETION_CODE_SUCCESS_CLOSE_UI	= ( COMPLETION_CODE_SUCCESS + 1 ) ,

@@ -4838,8 +4951,8 @@
 

 

 

-extern RPC_IF_HANDLE __MIDL_itf_google_update_idl_0000_0022_v0_0_c_ifspec;

-extern RPC_IF_HANDLE __MIDL_itf_google_update_idl_0000_0022_v0_0_s_ifspec;

+extern RPC_IF_HANDLE __MIDL_itf_google_update_idl_0000_0023_v0_0_c_ifspec;

+extern RPC_IF_HANDLE __MIDL_itf_google_update_idl_0000_0023_v0_0_s_ifspec;

 

 #ifndef __IProgressWndEvents_INTERFACE_DEFINED__

 #define __IProgressWndEvents_INTERFACE_DEFINED__

@@ -4852,7 +4965,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("e55b90f1-da33-400b-b09e-3aff7d46bd83")

+    MIDL_INTERFACE("1C642CED-CA3B-4013-A9DF-CA6CE5FF6503")

     IProgressWndEvents : public IUnknown

     {

     public:

@@ -4972,7 +5085,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("99f8e195-1042-4f89-a28c-89cdb74a14ae")

+    MIDL_INTERFACE("49D7563B-2DDB-4831-88C8-768A53833837")

     IJobObserver : public IUnknown

     {

     public:

@@ -5134,7 +5247,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("d9aa3288-4ea7-4e67-ae60-d18eadcb923d")

+    MIDL_INTERFACE("19692F10-ADD2-4EFF-BE54-E61C62E40D13")

     IJobObserver2 : public IUnknown

     {

     public:

@@ -5216,7 +5329,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("79e0c401-b7bc-4de5-8104-71350f3a9b67")

+    MIDL_INTERFACE("31AC3F11-E5EA-4a85-8A3D-8E095A39C27B")

     IGoogleUpdate : public IUnknown

     {

     public:

@@ -5310,7 +5423,7 @@
 

 #if defined(__cplusplus) && !defined(CINTERFACE)

     

-    MIDL_INTERFACE("fce48f77-c677-4012-8a1a-54d2e2bc07bd")

+    MIDL_INTERFACE("909489C2-85A6-4322-AA56-D25278649D67")

     IGoogleUpdateCore : public IUnknown

     {

     public:

@@ -5414,7 +5527,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("59e5039b-6524-481c-a78c-e680d7bf086c")

+class DECLSPEC_UUID("022105BD-948A-40c9-AB42-A3300DDF097F")

 GoogleUpdate3UserClass;

 #endif

 

@@ -5422,7 +5535,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("cecddd22-2e72-4832-9606-a9b0e5e344b2")

+class DECLSPEC_UUID("4EB61BAC-A3B6-4760-9581-655041EF4D69")

 GoogleUpdate3ServiceClass;

 #endif

 

@@ -5430,7 +5543,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("02fcf358-fc8a-4ce4-ad4f-e29cd2d17a58")

+class DECLSPEC_UUID("22181302-A8A6-4f84-A541-E5CBFC70CC43")

 GoogleUpdate3WebUserClass;

 #endif

 

@@ -5438,7 +5551,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("492e1c30-a1a2-4695-87c8-7a8cad6f936f")

+class DECLSPEC_UUID("8A1D4361-2C08-4700-A351-3EAA9CBFF5E4")

 GoogleUpdate3WebMachineClass;

 #endif

 

@@ -5446,7 +5559,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("ea92a799-267e-4df5-a6ed-6a7e0684bb8a")

+class DECLSPEC_UUID("534F5323-3569-4f42-919D-1E1CF93E5BF6")

 GoogleUpdate3WebServiceClass;

 #endif

 

@@ -5454,7 +5567,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("e421557c-0628-43fb-bf2b-7c9f8a4d067c")

+class DECLSPEC_UUID("598FE0E5-E02D-465d-9A9D-37974A28FD42")

 GoogleUpdate3WebMachineFallbackClass;

 #endif

 

@@ -5462,7 +5575,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("5ea43877-c6d8-4885-b77a-c0bb27e94372")

+class DECLSPEC_UUID("E8CF3E55-F919-49d9-ABC0-948E6CB34B9F")

 CurrentStateUserClass;

 #endif

 

@@ -5470,7 +5583,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("a2f5cb38-265f-4a02-9d1e-f25b664968ab")

+class DECLSPEC_UUID("9D6AA569-9F30-41ad-885A-346685C74928")

 CurrentStateMachineClass;

 #endif

 

@@ -5478,7 +5591,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("5e2e78d4-43e7-4a98-b609-6089768f87f2")

+class DECLSPEC_UUID("7DE94008-8AFD-4c70-9728-C6FBFFF6A73E")

 CoCreateAsyncClass;

 #endif

 

@@ -5486,7 +5599,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("2f49c178-f8bf-43fd-b8f2-1a5b9d6bad8e")

+class DECLSPEC_UUID("e67be843-bbbe-4484-95fb-05271ae86750")

 CredentialDialogUserClass;

 #endif

 

@@ -5494,7 +5607,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("5f6a18bb-6231-424b-8242-19e5bb94f8ed")

+class DECLSPEC_UUID("25461599-633d-42b1-84fb-7cd68d026e53")

 CredentialDialogMachineClass;

 #endif

 

@@ -5502,15 +5615,31 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("08d832b9-d2fd-481f-98cf-904d00df63cc")

+class DECLSPEC_UUID("ABC01078-F197-4b0b-ADBC-CFE684B39C82")

 ProcessLauncherClass;

 #endif

 

+EXTERN_C const CLSID CLSID_OneClickUserProcessLauncherClass;

+

+#ifdef __cplusplus

+

+class DECLSPEC_UUID("51F9E8EF-59D7-475b-A106-C7EA6F30C119")

+OneClickUserProcessLauncherClass;

+#endif

+

+EXTERN_C const CLSID CLSID_OneClickMachineProcessLauncherClass;

+

+#ifdef __cplusplus

+

+class DECLSPEC_UUID("AAD4AE2E-D834-46d4-8B09-490FAC9C722B")

+OneClickMachineProcessLauncherClass;

+#endif

+

 EXTERN_C const CLSID CLSID_OnDemandUserAppsClass;

 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("e0dcae7c-1d0a-4ad0-b92c-2ffdaee1562b")

+class DECLSPEC_UUID("2F0E2680-9FF5-43c0-B76E-114A56E93598")

 OnDemandUserAppsClass;

 #endif

 

@@ -5518,7 +5647,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("d1e8b1a6-32ce-443c-8e2e-eba90c481353")

+class DECLSPEC_UUID("6F8BD55B-E83D-4a47-85BE-81FFA8057A69")

 OnDemandMachineAppsClass;

 #endif

 

@@ -5526,7 +5655,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("a6b716cb-028b-404d-b72c-50e153dd68da")

+class DECLSPEC_UUID("9465B4B4-5216-4042-9A2C-754D3BCDC410")

 OnDemandMachineAppsServiceClass;

 #endif

 

@@ -5534,7 +5663,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("ff419ff9-90be-4d9f-b410-a789f90e5a7c")

+class DECLSPEC_UUID("B3D28DBD-0DFA-40e4-8071-520767BADC7E")

 OnDemandMachineAppsFallbackClass;

 #endif

 

@@ -5542,7 +5671,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("8f09cd6c-5964-4573-82e3-ebff7702865b")

+class DECLSPEC_UUID("E225E692-4B47-4777-9BED-4FD7FE257F0E")

 GoogleUpdateCoreClass;

 #endif

 

@@ -5550,7 +5679,7 @@
 

 #ifdef __cplusplus

 

-class DECLSPEC_UUID("2e1dd7ef-c12d-4f8e-8ad8-cf8cc265bad0")

+class DECLSPEC_UUID("9B2340A0-4068-43d6-B404-32E27217859D")

 GoogleUpdateCoreMachineClass;

 #endif

 #endif /* __GoogleUpdate3Lib_LIBRARY_DEFINED__ */

diff --git a/third_party/win_build_output/midl/google_update/arm64/google_update_idl.tlb b/third_party/win_build_output/midl/google_update/arm64/google_update_idl.tlb
index f755405..1e734a0 100644
--- a/third_party/win_build_output/midl/google_update/arm64/google_update_idl.tlb
+++ b/third_party/win_build_output/midl/google_update/arm64/google_update_idl.tlb
Binary files differ
diff --git a/third_party/win_build_output/midl/google_update/arm64/google_update_idl_i.c b/third_party/win_build_output/midl/google_update/arm64/google_update_idl_i.c
index 56edce1..0cbd38e4 100644
--- a/third_party/win_build_output/midl/google_update/arm64/google_update_idl_i.c
+++ b/third_party/win_build_output/midl/google_update/arm64/google_update_idl_i.c
@@ -67,142 +67,151 @@
 

 #endif // !_MIDL_USE_GUIDDEF_

 

-MIDL_DEFINE_GUID(IID, IID_IGoogleUpdate3,0xddd4b5d4,0xfd54,0x497c,0x87,0x89,0x08,0x30,0xf2,0x9a,0x60,0xee);

+MIDL_DEFINE_GUID(IID, IID_IGoogleUpdate3,0x6DB17455,0x4E85,0x46e7,0x9D,0x23,0xE5,0x55,0xE4,0xB0,0x05,0xAF);

 

 

-MIDL_DEFINE_GUID(IID, IID_IAppBundle,0xab4f4a7e,0x977c,0x4e23,0xad,0x8f,0x62,0x6a,0x49,0x17,0x15,0xdf);

+MIDL_DEFINE_GUID(IID, IID_IAppBundle,0xfe908cdd,0x22bb,0x472a,0x98,0x70,0x1a,0x03,0x90,0xe4,0x2f,0x36);

 

 

-MIDL_DEFINE_GUID(IID, IID_IApp,0x195a2eb3,0x21ee,0x43ca,0x9f,0x23,0x93,0xc2,0xc9,0x93,0x4e,0x2e);

+MIDL_DEFINE_GUID(IID, IID_IApp,0x76F7B787,0xA67C,0x4c73,0x82,0xC7,0x31,0xF5,0xE3,0xAA,0xBC,0x5C);

 

 

-MIDL_DEFINE_GUID(IID, IID_IApp2,0xc06ee550,0x7248,0x488e,0x97,0x1e,0xb6,0x0c,0x0a,0xb3,0xa6,0xe4);

+MIDL_DEFINE_GUID(IID, IID_IApp2,0x084D78A8,0xB084,0x4E14,0xA6,0x29,0xA2,0xC4,0x19,0xB0,0xE3,0xD9);

 

 

-MIDL_DEFINE_GUID(IID, IID_IAppCommand,0x5f9c80b5,0x9e50,0x43c9,0x88,0x7c,0x7c,0x64,0x12,0xe1,0x10,0xdf);

+MIDL_DEFINE_GUID(IID, IID_IAppCommand,0x4DE778FE,0xF195,0x4ee3,0x9D,0xAB,0xFE,0x44,0x6C,0x23,0x92,0x21);

 

 

-MIDL_DEFINE_GUID(IID, IID_IAppCommand2,0x7e29be61,0x5809,0x443f,0x9b,0x5d,0xcf,0x22,0x15,0x66,0x94,0xeb);

+MIDL_DEFINE_GUID(IID, IID_IAppCommand2,0x3D05F64F,0x71E3,0x48A5,0xBF,0x6B,0x83,0x31,0x5B,0xC8,0xAE,0x1F);

 

 

-MIDL_DEFINE_GUID(IID, IID_IAppVersion,0x7b3b7a69,0x7d88,0x4847,0xa6,0xbc,0x90,0xe2,0x46,0xa4,0x1f,0x69);

+MIDL_DEFINE_GUID(IID, IID_IAppVersion,0xBCDCB538,0x01C0,0x46d1,0xA6,0xA7,0x52,0xF4,0xD0,0x21,0xC2,0x72);

 

 

-MIDL_DEFINE_GUID(IID, IID_IPackage,0xc853632e,0x36ca,0x4999,0xb9,0x92,0xec,0x0d,0x40,0x8c,0xf5,0xab);

+MIDL_DEFINE_GUID(IID, IID_IPackage,0xDCAB8386,0x4F03,0x4dbd,0xA3,0x66,0xD9,0x0B,0xC9,0xF6,0x8D,0xE6);

 

 

-MIDL_DEFINE_GUID(IID, IID_ICurrentState,0x177cae89,0x4ad6,0x42f4,0xa4,0x58,0x00,0xec,0x33,0x89,0xe3,0xfe);

+MIDL_DEFINE_GUID(IID, IID_ICurrentState,0x247954F9,0x9EDC,0x4E68,0x8C,0xC3,0x15,0x0C,0x2B,0x89,0xEA,0xDF);

 

 

-MIDL_DEFINE_GUID(IID, IID_IRegistrationUpdateHook,0x3e102dc6,0x1edb,0x46a1,0x84,0x88,0x61,0xf7,0x1b,0x35,0xed,0x5f);

+MIDL_DEFINE_GUID(IID, IID_IRegistrationUpdateHook,0x4E223325,0xC16B,0x4eeb,0xAE,0xDC,0x19,0xAA,0x99,0xA2,0x37,0xFA);

 

 

-MIDL_DEFINE_GUID(IID, IID_ICredentialDialog,0x2603c88b,0xf971,0x4167,0x9d,0xe1,0x87,0x1e,0xe4,0xa3,0xdc,0x84);

+MIDL_DEFINE_GUID(IID, IID_ICredentialDialog,0xb3a47570,0x0a85,0x4aea,0x82,0x70,0x52,0x9d,0x47,0x89,0x96,0x03);

 

 

-MIDL_DEFINE_GUID(IID, IID_IGoogleUpdate3Web,0x6dffe7fe,0x3153,0x4af1,0x95,0xd8,0xf8,0xfc,0xca,0x97,0xe5,0x6b);

+MIDL_DEFINE_GUID(IID, IID_IGoogleUpdate3Web,0x494B20CF,0x282E,0x4BDD,0x9F,0x5D,0xB7,0x0C,0xB0,0x9D,0x35,0x1E);

 

 

-MIDL_DEFINE_GUID(IID, IID_IGoogleUpdate3WebSecurity,0x1b9063e4,0x3882,0x485e,0x87,0x97,0xf2,0x8a,0x02,0x40,0x78,0x2f);

+MIDL_DEFINE_GUID(IID, IID_IGoogleUpdate3WebSecurity,0x2D363682,0x561D,0x4c3a,0x81,0xC6,0xF2,0xF8,0x21,0x07,0x56,0x2A);

 

 

-MIDL_DEFINE_GUID(IID, IID_IAppBundleWeb,0x837e40da,0xeb1b,0x440c,0x86,0x23,0x0f,0x14,0xdf,0x15,0x8d,0xc0);

+MIDL_DEFINE_GUID(IID, IID_IAppBundleWeb,0xDD42475D,0x6D46,0x496a,0x92,0x4E,0xBD,0x56,0x30,0xB4,0xCB,0xBA);

 

 

-MIDL_DEFINE_GUID(IID, IID_IAppWeb,0x3a49f783,0x1c7d,0x4d35,0x8f,0x63,0x5c,0x1c,0x20,0x6b,0x9b,0x6e);

+MIDL_DEFINE_GUID(IID, IID_IAppWeb,0x18D0F672,0x18B4,0x48e6,0xAD,0x36,0x6E,0x6B,0xF0,0x1D,0xBB,0xC4);

 

 

-MIDL_DEFINE_GUID(IID, IID_IAppCommandWeb,0x2ec826cb,0x5478,0x4533,0x90,0x15,0x75,0x80,0xb3,0xb5,0xe0,0x3a);

+MIDL_DEFINE_GUID(IID, IID_IAppCommandWeb,0x8476CE12,0xAE1F,0x4198,0x80,0x5C,0xBA,0x0F,0x9B,0x78,0x3F,0x57);

 

 

-MIDL_DEFINE_GUID(IID, IID_IAppVersionWeb,0x450cf5ff,0x95c4,0x4679,0xbe,0xca,0x22,0x68,0x03,0x89,0xec,0xb9);

+MIDL_DEFINE_GUID(IID, IID_IAppVersionWeb,0x0CD01D1E,0x4A1C,0x489d,0x93,0xB9,0x9B,0x66,0x72,0x87,0x7C,0x57);

 

 

-MIDL_DEFINE_GUID(IID, IID_ICoCreateAsyncStatus,0x9a6b447a,0x35e2,0x4f6b,0xa8,0x7b,0x5d,0xee,0xbb,0xfd,0xad,0x17);

+MIDL_DEFINE_GUID(IID, IID_ICoCreateAsyncStatus,0x2E629606,0x312A,0x482f,0x9B,0x12,0x2C,0x4A,0xBF,0x6F,0x0B,0x6D);

 

 

-MIDL_DEFINE_GUID(IID, IID_ICoCreateAsync,0xc20433b3,0x0d4b,0x49f6,0x9b,0x6c,0x6e,0xe0,0xfa,0xe0,0x78,0x37);

+MIDL_DEFINE_GUID(IID, IID_ICoCreateAsync,0xDAB1D343,0x1B2A,0x47f9,0xB4,0x45,0x93,0xDC,0x50,0x70,0x4B,0xFE);

 

 

-MIDL_DEFINE_GUID(IID, IID_IBrowserHttpRequest2,0xe4518371,0x7326,0x4865,0x87,0xf8,0xd9,0xd3,0xf3,0xb2,0x87,0xa3);

+MIDL_DEFINE_GUID(IID, IID_IBrowserHttpRequest2,0x5B25A8DC,0x1780,0x4178,0xA6,0x29,0x6B,0xE8,0xB8,0xDE,0xFA,0xA2);

 

 

-MIDL_DEFINE_GUID(IID, IID_IProcessLauncher,0xa5135e58,0x384f,0x4244,0x9a,0x5f,0x30,0xfa,0x92,0x59,0x41,0x3c);

+MIDL_DEFINE_GUID(IID, IID_IProcessLauncher,0x128C2DA6,0x2BC0,0x44c0,0xB3,0xF6,0x4E,0xC2,0x2E,0x64,0x79,0x64);

 

 

-MIDL_DEFINE_GUID(IID, IID_IProcessLauncher2,0xa6556dff,0xab15,0x4dc3,0xa8,0x90,0xab,0x54,0x12,0x0b,0xea,0xec);

+MIDL_DEFINE_GUID(IID, IID_IProcessLauncher2,0xD106AB5F,0xA70E,0x400E,0xA2,0x1B,0x96,0x20,0x8C,0x1D,0x8D,0xBB);

+

+

+MIDL_DEFINE_GUID(IID, IID_IOneClickProcessLauncher,0x5CCCB0EF,0x7073,0x4516,0x80,0x28,0x4C,0x62,0x8D,0x0C,0x8A,0xAB);

+

+

+MIDL_DEFINE_GUID(IID, IID_IProgressWndEvents,0x1C642CED,0xCA3B,0x4013,0xA9,0xDF,0xCA,0x6C,0xE5,0xFF,0x65,0x03);

+

+

+MIDL_DEFINE_GUID(IID, IID_IJobObserver,0x49D7563B,0x2DDB,0x4831,0x88,0xC8,0x76,0x8A,0x53,0x83,0x38,0x37);

 

 

-MIDL_DEFINE_GUID(IID, IID_IProgressWndEvents,0xe55b90f1,0xda33,0x400b,0xb0,0x9e,0x3a,0xff,0x7d,0x46,0xbd,0x83);

+MIDL_DEFINE_GUID(IID, IID_IJobObserver2,0x19692F10,0xADD2,0x4EFF,0xBE,0x54,0xE6,0x1C,0x62,0xE4,0x0D,0x13);

 

 

-MIDL_DEFINE_GUID(IID, IID_IJobObserver,0x99f8e195,0x1042,0x4f89,0xa2,0x8c,0x89,0xcd,0xb7,0x4a,0x14,0xae);

+MIDL_DEFINE_GUID(IID, IID_IGoogleUpdate,0x31AC3F11,0xE5EA,0x4a85,0x8A,0x3D,0x8E,0x09,0x5A,0x39,0xC2,0x7B);

 

 

-MIDL_DEFINE_GUID(IID, IID_IJobObserver2,0xd9aa3288,0x4ea7,0x4e67,0xae,0x60,0xd1,0x8e,0xad,0xcb,0x92,0x3d);

+MIDL_DEFINE_GUID(IID, IID_IGoogleUpdateCore,0x909489C2,0x85A6,0x4322,0xAA,0x56,0xD2,0x52,0x78,0x64,0x9D,0x67);

 

 

-MIDL_DEFINE_GUID(IID, IID_IGoogleUpdate,0x79e0c401,0xb7bc,0x4de5,0x81,0x04,0x71,0x35,0x0f,0x3a,0x9b,0x67);

+MIDL_DEFINE_GUID(IID, LIBID_GoogleUpdate3Lib,0x655DD85A,0x3C0D,0x4674,0x9C,0x58,0xAF,0x71,0x68,0xC5,0x86,0x1E);

 

 

-MIDL_DEFINE_GUID(IID, IID_IGoogleUpdateCore,0xfce48f77,0xc677,0x4012,0x8a,0x1a,0x54,0xd2,0xe2,0xbc,0x07,0xbd);

+MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3UserClass,0x022105BD,0x948A,0x40c9,0xAB,0x42,0xA3,0x30,0x0D,0xDF,0x09,0x7F);

 

 

-MIDL_DEFINE_GUID(IID, LIBID_GoogleUpdate3Lib,0xf27928c7,0xea56,0x4faf,0x8a,0xfa,0x1c,0x3c,0x73,0x48,0xc7,0x4d);

+MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3ServiceClass,0x4EB61BAC,0xA3B6,0x4760,0x95,0x81,0x65,0x50,0x41,0xEF,0x4D,0x69);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3UserClass,0x59e5039b,0x6524,0x481c,0xa7,0x8c,0xe6,0x80,0xd7,0xbf,0x08,0x6c);

+MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3WebUserClass,0x22181302,0xA8A6,0x4f84,0xA5,0x41,0xE5,0xCB,0xFC,0x70,0xCC,0x43);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3ServiceClass,0xcecddd22,0x2e72,0x4832,0x96,0x06,0xa9,0xb0,0xe5,0xe3,0x44,0xb2);

+MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3WebMachineClass,0x8A1D4361,0x2C08,0x4700,0xA3,0x51,0x3E,0xAA,0x9C,0xBF,0xF5,0xE4);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3WebUserClass,0x02fcf358,0xfc8a,0x4ce4,0xad,0x4f,0xe2,0x9c,0xd2,0xd1,0x7a,0x58);

+MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3WebServiceClass,0x534F5323,0x3569,0x4f42,0x91,0x9D,0x1E,0x1C,0xF9,0x3E,0x5B,0xF6);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3WebMachineClass,0x492e1c30,0xa1a2,0x4695,0x87,0xc8,0x7a,0x8c,0xad,0x6f,0x93,0x6f);

+MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3WebMachineFallbackClass,0x598FE0E5,0xE02D,0x465d,0x9A,0x9D,0x37,0x97,0x4A,0x28,0xFD,0x42);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3WebServiceClass,0xea92a799,0x267e,0x4df5,0xa6,0xed,0x6a,0x7e,0x06,0x84,0xbb,0x8a);

+MIDL_DEFINE_GUID(CLSID, CLSID_CurrentStateUserClass,0xE8CF3E55,0xF919,0x49d9,0xAB,0xC0,0x94,0x8E,0x6C,0xB3,0x4B,0x9F);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdate3WebMachineFallbackClass,0xe421557c,0x0628,0x43fb,0xbf,0x2b,0x7c,0x9f,0x8a,0x4d,0x06,0x7c);

+MIDL_DEFINE_GUID(CLSID, CLSID_CurrentStateMachineClass,0x9D6AA569,0x9F30,0x41ad,0x88,0x5A,0x34,0x66,0x85,0xC7,0x49,0x28);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_CurrentStateUserClass,0x5ea43877,0xc6d8,0x4885,0xb7,0x7a,0xc0,0xbb,0x27,0xe9,0x43,0x72);

+MIDL_DEFINE_GUID(CLSID, CLSID_CoCreateAsyncClass,0x7DE94008,0x8AFD,0x4c70,0x97,0x28,0xC6,0xFB,0xFF,0xF6,0xA7,0x3E);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_CurrentStateMachineClass,0xa2f5cb38,0x265f,0x4a02,0x9d,0x1e,0xf2,0x5b,0x66,0x49,0x68,0xab);

+MIDL_DEFINE_GUID(CLSID, CLSID_CredentialDialogUserClass,0xe67be843,0xbbbe,0x4484,0x95,0xfb,0x05,0x27,0x1a,0xe8,0x67,0x50);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_CoCreateAsyncClass,0x5e2e78d4,0x43e7,0x4a98,0xb6,0x09,0x60,0x89,0x76,0x8f,0x87,0xf2);

+MIDL_DEFINE_GUID(CLSID, CLSID_CredentialDialogMachineClass,0x25461599,0x633d,0x42b1,0x84,0xfb,0x7c,0xd6,0x8d,0x02,0x6e,0x53);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_CredentialDialogUserClass,0x2f49c178,0xf8bf,0x43fd,0xb8,0xf2,0x1a,0x5b,0x9d,0x6b,0xad,0x8e);

+MIDL_DEFINE_GUID(CLSID, CLSID_ProcessLauncherClass,0xABC01078,0xF197,0x4b0b,0xAD,0xBC,0xCF,0xE6,0x84,0xB3,0x9C,0x82);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_CredentialDialogMachineClass,0x5f6a18bb,0x6231,0x424b,0x82,0x42,0x19,0xe5,0xbb,0x94,0xf8,0xed);

+MIDL_DEFINE_GUID(CLSID, CLSID_OneClickUserProcessLauncherClass,0x51F9E8EF,0x59D7,0x475b,0xA1,0x06,0xC7,0xEA,0x6F,0x30,0xC1,0x19);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_ProcessLauncherClass,0x08d832b9,0xd2fd,0x481f,0x98,0xcf,0x90,0x4d,0x00,0xdf,0x63,0xcc);

+MIDL_DEFINE_GUID(CLSID, CLSID_OneClickMachineProcessLauncherClass,0xAAD4AE2E,0xD834,0x46d4,0x8B,0x09,0x49,0x0F,0xAC,0x9C,0x72,0x2B);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_OnDemandUserAppsClass,0xe0dcae7c,0x1d0a,0x4ad0,0xb9,0x2c,0x2f,0xfd,0xae,0xe1,0x56,0x2b);

+MIDL_DEFINE_GUID(CLSID, CLSID_OnDemandUserAppsClass,0x2F0E2680,0x9FF5,0x43c0,0xB7,0x6E,0x11,0x4A,0x56,0xE9,0x35,0x98);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_OnDemandMachineAppsClass,0xd1e8b1a6,0x32ce,0x443c,0x8e,0x2e,0xeb,0xa9,0x0c,0x48,0x13,0x53);

+MIDL_DEFINE_GUID(CLSID, CLSID_OnDemandMachineAppsClass,0x6F8BD55B,0xE83D,0x4a47,0x85,0xBE,0x81,0xFF,0xA8,0x05,0x7A,0x69);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_OnDemandMachineAppsServiceClass,0xa6b716cb,0x028b,0x404d,0xb7,0x2c,0x50,0xe1,0x53,0xdd,0x68,0xda);

+MIDL_DEFINE_GUID(CLSID, CLSID_OnDemandMachineAppsServiceClass,0x9465B4B4,0x5216,0x4042,0x9A,0x2C,0x75,0x4D,0x3B,0xCD,0xC4,0x10);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_OnDemandMachineAppsFallbackClass,0xff419ff9,0x90be,0x4d9f,0xb4,0x10,0xa7,0x89,0xf9,0x0e,0x5a,0x7c);

+MIDL_DEFINE_GUID(CLSID, CLSID_OnDemandMachineAppsFallbackClass,0xB3D28DBD,0x0DFA,0x40e4,0x80,0x71,0x52,0x07,0x67,0xBA,0xDC,0x7E);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdateCoreClass,0x8f09cd6c,0x5964,0x4573,0x82,0xe3,0xeb,0xff,0x77,0x02,0x86,0x5b);

+MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdateCoreClass,0xE225E692,0x4B47,0x4777,0x9B,0xED,0x4F,0xD7,0xFE,0x25,0x7F,0x0E);

 

 

-MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdateCoreMachineClass,0x2e1dd7ef,0xc12d,0x4f8e,0x8a,0xd8,0xcf,0x8c,0xc2,0x65,0xba,0xd0);

+MIDL_DEFINE_GUID(CLSID, CLSID_GoogleUpdateCoreMachineClass,0x9B2340A0,0x4068,0x43d6,0xB4,0x04,0x32,0xE2,0x72,0x17,0x85,0x9D);

 

 #undef MIDL_DEFINE_GUID

 

diff --git a/third_party/win_build_output/midl/google_update/arm64/google_update_idl_p.c b/third_party/win_build_output/midl/google_update/arm64/google_update_idl_p.c
index 5329b66..7182b95 100644
--- a/third_party/win_build_output/midl/google_update/arm64/google_update_idl_p.c
+++ b/third_party/win_build_output/midl/google_update/arm64/google_update_idl_p.c
@@ -47,7 +47,7 @@
 #include "google_update_idl.h"

 

 #define TYPE_FORMAT_STRING_SIZE   1117                              

-#define PROC_FORMAT_STRING_SIZE   5701                              

+#define PROC_FORMAT_STRING_SIZE   5749                              

 #define EXPR_FORMAT_STRING_SIZE   1                                 

 #define TRANSMIT_AS_TABLE_SIZE    0            

 #define WIRE_MARSHAL_TABLE_SIZE   2            

@@ -237,6 +237,13 @@
 extern const MIDL_STUB_DESC Object_StubDesc;

 

 

+extern const MIDL_SERVER_INFO IOneClickProcessLauncher_ServerInfo;

+extern const MIDL_STUBLESS_PROXY_INFO IOneClickProcessLauncher_ProxyInfo;

+

+

+extern const MIDL_STUB_DESC Object_StubDesc;

+

+

 extern const MIDL_SERVER_INFO IProgressWndEvents_ServerInfo;

 extern const MIDL_STUBLESS_PROXY_INFO IProgressWndEvents_ProxyInfo;

 

@@ -4857,27 +4864,68 @@
 /* 5032 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

-	/* Procedure OnShow */

-

-

-	/* Procedure DoClose */

+	/* Procedure LaunchAppCommand */

 

 /* 5034 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

 /* 5036 */	NdrFcLong( 0x0 ),	/* 0 */

 /* 5040 */	NdrFcShort( 0x3 ),	/* 3 */

-/* 5042 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5042 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

 /* 5044 */	NdrFcShort( 0x0 ),	/* 0 */

 /* 5046 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5048 */	0x44,		/* Oi2 Flags:  has return, has ext, */

-			0x1,		/* 1 */

-/* 5050 */	0xc,		/* 12 */

+/* 5048 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+			0x3,		/* 3 */

+/* 5050 */	0xe,		/* 14 */

 			0x1,		/* Ext Flags:  new corr desc, */

 /* 5052 */	NdrFcShort( 0x0 ),	/* 0 */

 /* 5054 */	NdrFcShort( 0x0 ),	/* 0 */

 /* 5056 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5058 */	NdrFcShort( 0x1 ),	/* 1 */

-/* 5060 */	0x1,		/* 1 */

+/* 5058 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 5060 */	0x3,		/* 3 */

+			0x80,		/* 128 */

+/* 5062 */	0x81,		/* 129 */

+			0x82,		/* 130 */

+

+	/* Parameter app_guid */

+

+/* 5064 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

+/* 5066 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5068 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

+

+	/* Parameter cmd_id */

+

+/* 5070 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

+/* 5072 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5074 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

+

+	/* Return value */

+

+/* 5076 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5078 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5080 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure OnShow */

+

+

+	/* Procedure DoClose */

+

+/* 5082 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 5084 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5088 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 5090 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5092 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5094 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5096 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+			0x1,		/* 1 */

+/* 5098 */	0xc,		/* 12 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 5100 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5102 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5104 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5106 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 5108 */	0x1,		/* 1 */

 			0x80,		/* 128 */

 

 	/* Return value */

@@ -4885,9 +4933,9 @@
 

 	/* Return value */

 

-/* 5062 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5064 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5066 */	0x8,		/* FC_LONG */

+/* 5110 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5112 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5114 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

 	/* Procedure OnCheckingForUpdate */

@@ -4895,22 +4943,22 @@
 

 	/* Procedure DoPause */

 

-/* 5068 */	0x33,		/* FC_AUTO_HANDLE */

+/* 5116 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

-/* 5070 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5074 */	NdrFcShort( 0x4 ),	/* 4 */

-/* 5076 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5078 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5080 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5082 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+/* 5118 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5122 */	NdrFcShort( 0x4 ),	/* 4 */

+/* 5124 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5126 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5128 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5130 */	0x44,		/* Oi2 Flags:  has return, has ext, */

 			0x1,		/* 1 */

-/* 5084 */	0xc,		/* 12 */

+/* 5132 */	0xc,		/* 12 */

 			0x1,		/* Ext Flags:  new corr desc, */

-/* 5086 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5088 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5090 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5092 */	NdrFcShort( 0x1 ),	/* 1 */

-/* 5094 */	0x1,		/* 1 */

+/* 5134 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5136 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5138 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5140 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 5142 */	0x1,		/* 1 */

 			0x80,		/* 128 */

 

 	/* Return value */

@@ -4918,36 +4966,36 @@
 

 	/* Return value */

 

-/* 5096 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5098 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5100 */	0x8,		/* FC_LONG */

+/* 5144 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5146 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5148 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

 	/* Procedure DoResume */

 

-/* 5102 */	0x33,		/* FC_AUTO_HANDLE */

+/* 5150 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

-/* 5104 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5108 */	NdrFcShort( 0x5 ),	/* 5 */

-/* 5110 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5112 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5114 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5116 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+/* 5152 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5156 */	NdrFcShort( 0x5 ),	/* 5 */

+/* 5158 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5160 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5162 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5164 */	0x44,		/* Oi2 Flags:  has return, has ext, */

 			0x1,		/* 1 */

-/* 5118 */	0xc,		/* 12 */

+/* 5166 */	0xc,		/* 12 */

 			0x1,		/* Ext Flags:  new corr desc, */

-/* 5120 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5122 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5124 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5126 */	NdrFcShort( 0x1 ),	/* 1 */

-/* 5128 */	0x1,		/* 1 */

+/* 5168 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5170 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5172 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5174 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 5176 */	0x1,		/* 1 */

 			0x80,		/* 128 */

 

 	/* Return value */

 

-/* 5130 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5132 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5134 */	0x8,		/* FC_LONG */

+/* 5178 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5180 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5182 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

 	/* Procedure OnWaitingToDownload */

@@ -4955,22 +5003,22 @@
 

 	/* Procedure DoRestartBrowsers */

 

-/* 5136 */	0x33,		/* FC_AUTO_HANDLE */

+/* 5184 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

-/* 5138 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5142 */	NdrFcShort( 0x6 ),	/* 6 */

-/* 5144 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5146 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5148 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5150 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+/* 5186 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5190 */	NdrFcShort( 0x6 ),	/* 6 */

+/* 5192 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5194 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5196 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5198 */	0x44,		/* Oi2 Flags:  has return, has ext, */

 			0x1,		/* 1 */

-/* 5152 */	0xc,		/* 12 */

+/* 5200 */	0xc,		/* 12 */

 			0x1,		/* Ext Flags:  new corr desc, */

-/* 5154 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5156 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5158 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5160 */	NdrFcShort( 0x1 ),	/* 1 */

-/* 5162 */	0x1,		/* 1 */

+/* 5202 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5204 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5206 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5208 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 5210 */	0x1,		/* 1 */

 			0x80,		/* 128 */

 

 	/* Return value */

@@ -4978,335 +5026,292 @@
 

 	/* Return value */

 

-/* 5164 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5166 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5168 */	0x8,		/* FC_LONG */

+/* 5212 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5214 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5216 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

 	/* Procedure DoReboot */

 

-/* 5170 */	0x33,		/* FC_AUTO_HANDLE */

+/* 5218 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

-/* 5172 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5176 */	NdrFcShort( 0x7 ),	/* 7 */

-/* 5178 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5180 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5182 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5184 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+/* 5220 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5224 */	NdrFcShort( 0x7 ),	/* 7 */

+/* 5226 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5228 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5230 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5232 */	0x44,		/* Oi2 Flags:  has return, has ext, */

 			0x1,		/* 1 */

-/* 5186 */	0xc,		/* 12 */

+/* 5234 */	0xc,		/* 12 */

 			0x1,		/* Ext Flags:  new corr desc, */

-/* 5188 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5190 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5192 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5194 */	NdrFcShort( 0x1 ),	/* 1 */

-/* 5196 */	0x1,		/* 1 */

+/* 5236 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5238 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5240 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5242 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 5244 */	0x1,		/* 1 */

 			0x80,		/* 128 */

 

 	/* Return value */

 

-/* 5198 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5200 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5202 */	0x8,		/* FC_LONG */

+/* 5246 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5248 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5250 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

 	/* Procedure DoLaunchBrowser */

 

-/* 5204 */	0x33,		/* FC_AUTO_HANDLE */

+/* 5252 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

-/* 5206 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5210 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5212 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

-/* 5214 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5216 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5218 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+/* 5254 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5258 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5260 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5262 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5264 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5266 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

 			0x2,		/* 2 */

-/* 5220 */	0xe,		/* 14 */

+/* 5268 */	0xe,		/* 14 */

 			0x1,		/* Ext Flags:  new corr desc, */

-/* 5222 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5224 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5226 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5228 */	NdrFcShort( 0x2 ),	/* 2 */

-/* 5230 */	0x2,		/* 2 */

+/* 5270 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5272 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5274 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5276 */	NdrFcShort( 0x2 ),	/* 2 */

+/* 5278 */	0x2,		/* 2 */

 			0x80,		/* 128 */

-/* 5232 */	0x81,		/* 129 */

+/* 5280 */	0x81,		/* 129 */

 			0x0,		/* 0 */

 

 	/* Parameter url */

 

-/* 5234 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

-/* 5236 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5238 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

+/* 5282 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

+/* 5284 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5286 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

 

 	/* Return value */

 

-/* 5240 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5242 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5244 */	0x8,		/* FC_LONG */

+/* 5288 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5290 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5292 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

 	/* Procedure OnUpdateAvailable */

 

-/* 5246 */	0x33,		/* FC_AUTO_HANDLE */

+/* 5294 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

-/* 5248 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5252 */	NdrFcShort( 0x5 ),	/* 5 */

-/* 5254 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

-/* 5256 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5258 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5260 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+/* 5296 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5300 */	NdrFcShort( 0x5 ),	/* 5 */

+/* 5302 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5304 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5306 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5308 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

 			0x2,		/* 2 */

-/* 5262 */	0xe,		/* 14 */

+/* 5310 */	0xe,		/* 14 */

 			0x1,		/* Ext Flags:  new corr desc, */

-/* 5264 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5266 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5268 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5270 */	NdrFcShort( 0x2 ),	/* 2 */

-/* 5272 */	0x2,		/* 2 */

+/* 5312 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5314 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5316 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5318 */	NdrFcShort( 0x2 ),	/* 2 */

+/* 5320 */	0x2,		/* 2 */

 			0x80,		/* 128 */

-/* 5274 */	0x81,		/* 129 */

+/* 5322 */	0x81,		/* 129 */

 			0x0,		/* 0 */

 

 	/* Parameter version_string */

 

-/* 5276 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

-/* 5278 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5280 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

-

-	/* Return value */

-

-/* 5282 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5284 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5286 */	0x8,		/* FC_LONG */

-			0x0,		/* 0 */

-

-	/* Procedure OnDownloading */

-

-/* 5288 */	0x33,		/* FC_AUTO_HANDLE */

-			0x6c,		/* Old Flags:  object, Oi2 */

-/* 5290 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5294 */	NdrFcShort( 0x7 ),	/* 7 */

-/* 5296 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

-/* 5298 */	NdrFcShort( 0x10 ),	/* 16 */

-/* 5300 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5302 */	0x44,		/* Oi2 Flags:  has return, has ext, */

-			0x3,		/* 3 */

-/* 5304 */	0xe,		/* 14 */

-			0x1,		/* Ext Flags:  new corr desc, */

-/* 5306 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5308 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5310 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5312 */	NdrFcShort( 0x3 ),	/* 3 */

-/* 5314 */	0x3,		/* 3 */

-			0x80,		/* 128 */

-/* 5316 */	0x81,		/* 129 */

-			0x82,		/* 130 */

-

-	/* Parameter time_remaining_ms */

-

-/* 5318 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

-/* 5320 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5322 */	0x8,		/* FC_LONG */

-			0x0,		/* 0 */

-

-	/* Parameter pos */

-

-/* 5324 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

-/* 5326 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5328 */	0x8,		/* FC_LONG */

-			0x0,		/* 0 */

+/* 5324 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

+/* 5326 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5328 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

 

 	/* Return value */

 

 /* 5330 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5332 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5332 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

 /* 5334 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

-	/* Procedure OnWaitingToInstall */

+	/* Procedure OnDownloading */

 

 /* 5336 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

 /* 5338 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5342 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5344 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5346 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5342 */	NdrFcShort( 0x7 ),	/* 7 */

+/* 5344 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

+/* 5346 */	NdrFcShort( 0x10 ),	/* 16 */

 /* 5348 */	NdrFcShort( 0x8 ),	/* 8 */

 /* 5350 */	0x44,		/* Oi2 Flags:  has return, has ext, */

-			0x1,		/* 1 */

-/* 5352 */	0xc,		/* 12 */

+			0x3,		/* 3 */

+/* 5352 */	0xe,		/* 14 */

 			0x1,		/* Ext Flags:  new corr desc, */

 /* 5354 */	NdrFcShort( 0x0 ),	/* 0 */

 /* 5356 */	NdrFcShort( 0x0 ),	/* 0 */

 /* 5358 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5360 */	NdrFcShort( 0x1 ),	/* 1 */

-/* 5362 */	0x1,		/* 1 */

+/* 5360 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 5362 */	0x3,		/* 3 */

+			0x80,		/* 128 */

+/* 5364 */	0x81,		/* 129 */

+			0x82,		/* 130 */

+

+	/* Parameter time_remaining_ms */

+

+/* 5366 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 5368 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5370 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter pos */

+

+/* 5372 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 5374 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5376 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Return value */

+

+/* 5378 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5380 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5382 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure OnWaitingToInstall */

+

+/* 5384 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 5386 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5390 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5392 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5394 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5396 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5398 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+			0x1,		/* 1 */

+/* 5400 */	0xc,		/* 12 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 5402 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5404 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5406 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5408 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 5410 */	0x1,		/* 1 */

 			0x80,		/* 128 */

 

 	/* Return value */

 

-/* 5364 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5366 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5368 */	0x8,		/* FC_LONG */

+/* 5412 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5414 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5416 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

 	/* Procedure OnPause */

 

-/* 5370 */	0x33,		/* FC_AUTO_HANDLE */

+/* 5418 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

-/* 5372 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5376 */	NdrFcShort( 0xa ),	/* 10 */

-/* 5378 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5380 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5382 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5384 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+/* 5420 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5424 */	NdrFcShort( 0xa ),	/* 10 */

+/* 5426 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5428 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5430 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5432 */	0x44,		/* Oi2 Flags:  has return, has ext, */

 			0x1,		/* 1 */

-/* 5386 */	0xc,		/* 12 */

+/* 5434 */	0xc,		/* 12 */

 			0x1,		/* Ext Flags:  new corr desc, */

-/* 5388 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5390 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5392 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5394 */	NdrFcShort( 0x1 ),	/* 1 */

-/* 5396 */	0x1,		/* 1 */

+/* 5436 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5438 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5440 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5442 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 5444 */	0x1,		/* 1 */

 			0x80,		/* 128 */

 

 	/* Return value */

 

-/* 5398 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5400 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5402 */	0x8,		/* FC_LONG */

-			0x0,		/* 0 */

-

-	/* Procedure OnComplete */

-

-/* 5404 */	0x33,		/* FC_AUTO_HANDLE */

-			0x6c,		/* Old Flags:  object, Oi2 */

-/* 5406 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5410 */	NdrFcShort( 0xb ),	/* 11 */

-/* 5412 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

-/* 5414 */	NdrFcShort( 0x6 ),	/* 6 */

-/* 5416 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5418 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

-			0x3,		/* 3 */

-/* 5420 */	0xe,		/* 14 */

-			0x1,		/* Ext Flags:  new corr desc, */

-/* 5422 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5424 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5426 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5428 */	NdrFcShort( 0x3 ),	/* 3 */

-/* 5430 */	0x3,		/* 3 */

-			0x80,		/* 128 */

-/* 5432 */	0x81,		/* 129 */

-			0x82,		/* 130 */

-

-	/* Parameter code */

-

-/* 5434 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

-/* 5436 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5438 */	0xd,		/* FC_ENUM16 */

-			0x0,		/* 0 */

-

-	/* Parameter completion_text */

-

-/* 5440 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

-/* 5442 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5444 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

-

-	/* Return value */

-

 /* 5446 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5448 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5448 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

 /* 5450 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

-	/* Procedure SetEventSink */

+	/* Procedure OnComplete */

 

 /* 5452 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

 /* 5454 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5458 */	NdrFcShort( 0xc ),	/* 12 */

-/* 5460 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

-/* 5462 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5458 */	NdrFcShort( 0xb ),	/* 11 */

+/* 5460 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

+/* 5462 */	NdrFcShort( 0x6 ),	/* 6 */

 /* 5464 */	NdrFcShort( 0x8 ),	/* 8 */

 /* 5466 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

-			0x2,		/* 2 */

+			0x3,		/* 3 */

 /* 5468 */	0xe,		/* 14 */

 			0x1,		/* Ext Flags:  new corr desc, */

 /* 5470 */	NdrFcShort( 0x0 ),	/* 0 */

 /* 5472 */	NdrFcShort( 0x0 ),	/* 0 */

 /* 5474 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5476 */	NdrFcShort( 0x2 ),	/* 2 */

-/* 5478 */	0x2,		/* 2 */

+/* 5476 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 5478 */	0x3,		/* 3 */

 			0x80,		/* 128 */

 /* 5480 */	0x81,		/* 129 */

+			0x82,		/* 130 */

+

+	/* Parameter code */

+

+/* 5482 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 5484 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5486 */	0xd,		/* FC_ENUM16 */

+			0x0,		/* 0 */

+

+	/* Parameter completion_text */

+

+/* 5488 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

+/* 5490 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5492 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

+

+	/* Return value */

+

+/* 5494 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5496 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5498 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure SetEventSink */

+

+/* 5500 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 5502 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5506 */	NdrFcShort( 0xc ),	/* 12 */

+/* 5508 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5510 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5512 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5514 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+			0x2,		/* 2 */

+/* 5516 */	0xe,		/* 14 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 5518 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5520 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5522 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5524 */	NdrFcShort( 0x2 ),	/* 2 */

+/* 5526 */	0x2,		/* 2 */

+			0x80,		/* 128 */

+/* 5528 */	0x81,		/* 129 */

 			0x0,		/* 0 */

 

 	/* Parameter ui_sink */

 

-/* 5482 */	NdrFcShort( 0xb ),	/* Flags:  must size, must free, in, */

-/* 5484 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5486 */	NdrFcShort( 0x438 ),	/* Type Offset=1080 */

-

-	/* Return value */

-

-/* 5488 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5490 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5492 */	0x8,		/* FC_LONG */

-			0x0,		/* 0 */

-

-	/* Procedure OnInstalling2 */

-

-/* 5494 */	0x33,		/* FC_AUTO_HANDLE */

-			0x6c,		/* Old Flags:  object, Oi2 */

-/* 5496 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5500 */	NdrFcShort( 0x3 ),	/* 3 */

-/* 5502 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

-/* 5504 */	NdrFcShort( 0x10 ),	/* 16 */

-/* 5506 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5508 */	0x44,		/* Oi2 Flags:  has return, has ext, */

-			0x3,		/* 3 */

-/* 5510 */	0xe,		/* 14 */

-			0x1,		/* Ext Flags:  new corr desc, */

-/* 5512 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5514 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5516 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5518 */	NdrFcShort( 0x3 ),	/* 3 */

-/* 5520 */	0x3,		/* 3 */

-			0x80,		/* 128 */

-/* 5522 */	0x81,		/* 129 */

-			0x82,		/* 130 */

-

-	/* Parameter time_remaining_ms */

-

-/* 5524 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

-/* 5526 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5528 */	0x8,		/* FC_LONG */

-			0x0,		/* 0 */

-

-	/* Parameter pos */

-

-/* 5530 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

-/* 5532 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5534 */	0x8,		/* FC_LONG */

-			0x0,		/* 0 */

+/* 5530 */	NdrFcShort( 0xb ),	/* Flags:  must size, must free, in, */

+/* 5532 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5534 */	NdrFcShort( 0x438 ),	/* Type Offset=1080 */

 

 	/* Return value */

 

 /* 5536 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5538 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5538 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

 /* 5540 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

-	/* Procedure CheckForUpdate */

+	/* Procedure OnInstalling2 */

 

 /* 5542 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

 /* 5544 */	NdrFcLong( 0x0 ),	/* 0 */

 /* 5548 */	NdrFcShort( 0x3 ),	/* 3 */

 /* 5550 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

-/* 5552 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5552 */	NdrFcShort( 0x10 ),	/* 16 */

 /* 5554 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5556 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+/* 5556 */	0x44,		/* Oi2 Flags:  has return, has ext, */

 			0x3,		/* 3 */

 /* 5558 */	0xe,		/* 14 */

 			0x1,		/* Ext Flags:  new corr desc, */

@@ -5319,17 +5324,19 @@
 /* 5570 */	0x81,		/* 129 */

 			0x82,		/* 130 */

 

-	/* Parameter guid */

+	/* Parameter time_remaining_ms */

 

-/* 5572 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

+/* 5572 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

 /* 5574 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5576 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

+/* 5576 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

 

-	/* Parameter observer */

+	/* Parameter pos */

 

-/* 5578 */	NdrFcShort( 0xb ),	/* Flags:  must size, must free, in, */

+/* 5578 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

 /* 5580 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5582 */	NdrFcShort( 0x44a ),	/* Type Offset=1098 */

+/* 5582 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

 

 	/* Return value */

 

@@ -5338,12 +5345,12 @@
 /* 5588 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

-	/* Procedure Update */

+	/* Procedure CheckForUpdate */

 

 /* 5590 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

 /* 5592 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5596 */	NdrFcShort( 0x4 ),	/* 4 */

+/* 5596 */	NdrFcShort( 0x3 ),	/* 3 */

 /* 5598 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

 /* 5600 */	NdrFcShort( 0x0 ),	/* 0 */

 /* 5602 */	NdrFcShort( 0x8 ),	/* 8 */

@@ -5379,61 +5386,102 @@
 /* 5636 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

-	/* Procedure LaunchCmdElevated */

+	/* Procedure Update */

 

 /* 5638 */	0x33,		/* FC_AUTO_HANDLE */

 			0x6c,		/* Old Flags:  object, Oi2 */

 /* 5640 */	NdrFcLong( 0x0 ),	/* 0 */

-/* 5644 */	NdrFcShort( 0x3 ),	/* 3 */

-/* 5646 */	NdrFcShort( 0x30 ),	/* ARM64 Stack size/offset = 48 */

-/* 5648 */	NdrFcShort( 0x8 ),	/* 8 */

-/* 5650 */	NdrFcShort( 0x24 ),	/* 36 */

+/* 5644 */	NdrFcShort( 0x4 ),	/* 4 */

+/* 5646 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

+/* 5648 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5650 */	NdrFcShort( 0x8 ),	/* 8 */

 /* 5652 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

-			0x5,		/* 5 */

-/* 5654 */	0x10,		/* 16 */

+			0x3,		/* 3 */

+/* 5654 */	0xe,		/* 14 */

 			0x1,		/* Ext Flags:  new corr desc, */

 /* 5656 */	NdrFcShort( 0x0 ),	/* 0 */

 /* 5658 */	NdrFcShort( 0x0 ),	/* 0 */

 /* 5660 */	NdrFcShort( 0x0 ),	/* 0 */

-/* 5662 */	NdrFcShort( 0x5 ),	/* 5 */

-/* 5664 */	0x5,		/* 5 */

+/* 5662 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 5664 */	0x3,		/* 3 */

 			0x80,		/* 128 */

 /* 5666 */	0x81,		/* 129 */

 			0x82,		/* 130 */

-/* 5668 */	0x83,		/* 131 */

+

+	/* Parameter guid */

+

+/* 5668 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

+/* 5670 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5672 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

+

+	/* Parameter observer */

+

+/* 5674 */	NdrFcShort( 0xb ),	/* Flags:  must size, must free, in, */

+/* 5676 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5678 */	NdrFcShort( 0x44a ),	/* Type Offset=1098 */

+

+	/* Return value */

+

+/* 5680 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5682 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5684 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure LaunchCmdElevated */

+

+/* 5686 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 5688 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 5692 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 5694 */	NdrFcShort( 0x30 ),	/* ARM64 Stack size/offset = 48 */

+/* 5696 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 5698 */	NdrFcShort( 0x24 ),	/* 36 */

+/* 5700 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+			0x5,		/* 5 */

+/* 5702 */	0x10,		/* 16 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 5704 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5706 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5708 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 5710 */	NdrFcShort( 0x5 ),	/* 5 */

+/* 5712 */	0x5,		/* 5 */

+			0x80,		/* 128 */

+/* 5714 */	0x81,		/* 129 */

+			0x82,		/* 130 */

+/* 5716 */	0x83,		/* 131 */

 			0x84,		/* 132 */

 

 	/* Parameter app_guid */

 

-/* 5670 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

-/* 5672 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

-/* 5674 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

+/* 5718 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

+/* 5720 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 5722 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

 

 	/* Parameter cmd_id */

 

-/* 5676 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

-/* 5678 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

-/* 5680 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

+/* 5724 */	NdrFcShort( 0x10b ),	/* Flags:  must size, must free, in, simple ref, */

+/* 5726 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 5728 */	NdrFcShort( 0x432 ),	/* Type Offset=1074 */

 

 	/* Parameter caller_proc_id */

 

-/* 5682 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

-/* 5684 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

-/* 5686 */	0x8,		/* FC_LONG */

+/* 5730 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 5732 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 5734 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

 	/* Parameter proc_handle */

 

-/* 5688 */	NdrFcShort( 0x2150 ),	/* Flags:  out, base type, simple ref, srv alloc size=8 */

-/* 5690 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

-/* 5692 */	0xb9,		/* FC_UINT3264 */

+/* 5736 */	NdrFcShort( 0x2150 ),	/* Flags:  out, base type, simple ref, srv alloc size=8 */

+/* 5738 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

+/* 5740 */	0xb9,		/* FC_UINT3264 */

 			0x0,		/* 0 */

 

 	/* Return value */

 

-/* 5694 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

-/* 5696 */	NdrFcShort( 0x28 ),	/* ARM64 Stack size/offset = 40 */

-/* 5698 */	0x8,		/* FC_LONG */

+/* 5742 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 5744 */	NdrFcShort( 0x28 ),	/* ARM64 Stack size/offset = 40 */

+/* 5746 */	0x8,		/* FC_LONG */

 			0x0,		/* 0 */

 

 			0x0

@@ -6124,17 +6172,17 @@
 /* 1054 */	

 			0x2f,		/* FC_IP */

 			0x5a,		/* FC_CONSTANT_IID */

-/* 1056 */	NdrFcLong( 0x9a6b447a ),	/* -1704246150 */

-/* 1060 */	NdrFcShort( 0x35e2 ),	/* 13794 */

-/* 1062 */	NdrFcShort( 0x4f6b ),	/* 20331 */

-/* 1064 */	0xa8,		/* 168 */

-			0x7b,		/* 123 */

-/* 1066 */	0x5d,		/* 93 */

-			0xee,		/* 238 */

-/* 1068 */	0xbb,		/* 187 */

-			0xfd,		/* 253 */

-/* 1070 */	0xad,		/* 173 */

-			0x17,		/* 23 */

+/* 1056 */	NdrFcLong( 0x2e629606 ),	/* 778212870 */

+/* 1060 */	NdrFcShort( 0x312a ),	/* 12586 */

+/* 1062 */	NdrFcShort( 0x482f ),	/* 18479 */

+/* 1064 */	0x9b,		/* 155 */

+			0x12,		/* 18 */

+/* 1066 */	0x2c,		/* 44 */

+			0x4a,		/* 74 */

+/* 1068 */	0xbf,		/* 191 */

+			0x6f,		/* 111 */

+/* 1070 */	0xb,		/* 11 */

+			0x6d,		/* 109 */

 /* 1072 */	

 			0x11, 0x8,	/* FC_RP [simple_pointer] */

 /* 1074 */	

@@ -6147,31 +6195,31 @@
 /* 1080 */	

 			0x2f,		/* FC_IP */

 			0x5a,		/* FC_CONSTANT_IID */

-/* 1082 */	NdrFcLong( 0xe55b90f1 ),	/* -446983951 */

-/* 1086 */	NdrFcShort( 0xda33 ),	/* -9677 */

-/* 1088 */	NdrFcShort( 0x400b ),	/* 16395 */

-/* 1090 */	0xb0,		/* 176 */

-			0x9e,		/* 158 */

-/* 1092 */	0x3a,		/* 58 */

+/* 1082 */	NdrFcLong( 0x1c642ced ),	/* 476327149 */

+/* 1086 */	NdrFcShort( 0xca3b ),	/* -13765 */

+/* 1088 */	NdrFcShort( 0x4013 ),	/* 16403 */

+/* 1090 */	0xa9,		/* 169 */

+			0xdf,		/* 223 */

+/* 1092 */	0xca,		/* 202 */

+			0x6c,		/* 108 */

+/* 1094 */	0xe5,		/* 229 */

 			0xff,		/* 255 */

-/* 1094 */	0x7d,		/* 125 */

-			0x46,		/* 70 */

-/* 1096 */	0xbd,		/* 189 */

-			0x83,		/* 131 */

+/* 1096 */	0x65,		/* 101 */

+			0x3,		/* 3 */

 /* 1098 */	

 			0x2f,		/* FC_IP */

 			0x5a,		/* FC_CONSTANT_IID */

-/* 1100 */	NdrFcLong( 0x99f8e195 ),	/* -1711742571 */

-/* 1104 */	NdrFcShort( 0x1042 ),	/* 4162 */

-/* 1106 */	NdrFcShort( 0x4f89 ),	/* 20361 */

-/* 1108 */	0xa2,		/* 162 */

-			0x8c,		/* 140 */

-/* 1110 */	0x89,		/* 137 */

-			0xcd,		/* 205 */

-/* 1112 */	0xb7,		/* 183 */

-			0x4a,		/* 74 */

-/* 1114 */	0x14,		/* 20 */

-			0xae,		/* 174 */

+/* 1100 */	NdrFcLong( 0x49d7563b ),	/* 1238849083 */

+/* 1104 */	NdrFcShort( 0x2ddb ),	/* 11739 */

+/* 1106 */	NdrFcShort( 0x4831 ),	/* 18481 */

+/* 1108 */	0x88,		/* 136 */

+			0xc8,		/* 200 */

+/* 1110 */	0x76,		/* 118 */

+			0x8a,		/* 138 */

+/* 1112 */	0x53,		/* 83 */

+			0x83,		/* 131 */

+/* 1114 */	0x38,		/* 56 */

+			0x37,		/* 55 */

 

 			0x0

         }

@@ -6210,7 +6258,7 @@
 

 

 /* Object interface: IGoogleUpdate3, ver. 0.0,

-   GUID={0xddd4b5d4,0xfd54,0x497c,{0x87,0x89,0x08,0x30,0xf2,0x9a,0x60,0xee}} */

+   GUID={0x6DB17455,0x4E85,0x46e7,{0x9D,0x23,0xE5,0x55,0xE4,0xB0,0x05,0xAF}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IGoogleUpdate3_FormatStringOffsetTable[] =

@@ -6284,7 +6332,7 @@
 

 

 /* Object interface: IAppBundle, ver. 0.0,

-   GUID={0xab4f4a7e,0x977c,0x4e23,{0xad,0x8f,0x62,0x6a,0x49,0x17,0x15,0xdf}} */

+   GUID={0xfe908cdd,0x22bb,0x472a,{0x98,0x70,0x1a,0x03,0x90,0xe4,0x2f,0x36}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IAppBundle_FormatStringOffsetTable[] =

@@ -6451,7 +6499,7 @@
 

 

 /* Object interface: IApp, ver. 0.0,

-   GUID={0x195a2eb3,0x21ee,0x43ca,{0x9f,0x23,0x93,0xc2,0xc9,0x93,0x4e,0x2e}} */

+   GUID={0x76F7B787,0xA67C,0x4c73,{0x82,0xC7,0x31,0xF5,0xE3,0xAA,0xBC,0x5C}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IApp_FormatStringOffsetTable[] =

@@ -6618,7 +6666,7 @@
 

 

 /* Object interface: IApp2, ver. 0.0,

-   GUID={0xc06ee550,0x7248,0x488e,{0x97,0x1e,0xb6,0x0c,0x0a,0xb3,0xa6,0xe4}} */

+   GUID={0x084D78A8,0xB084,0x4E14,{0xA6,0x29,0xA2,0xC4,0x19,0xB0,0xE3,0xD9}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IApp2_FormatStringOffsetTable[] =

@@ -6791,7 +6839,7 @@
 

 

 /* Object interface: IAppCommand, ver. 0.0,

-   GUID={0x5f9c80b5,0x9e50,0x43c9,{0x88,0x7c,0x7c,0x64,0x12,0xe1,0x10,0xdf}} */

+   GUID={0x4DE778FE,0xF195,0x4ee3,{0x9D,0xAB,0xFE,0x44,0x6C,0x23,0x92,0x21}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IAppCommand_FormatStringOffsetTable[] =

@@ -6868,7 +6916,7 @@
 

 

 /* Object interface: IAppCommand2, ver. 0.0,

-   GUID={0x7e29be61,0x5809,0x443f,{0x9b,0x5d,0xcf,0x22,0x15,0x66,0x94,0xeb}} */

+   GUID={0x3D05F64F,0x71E3,0x48A5,{0xBF,0x6B,0x83,0x31,0x5B,0xC8,0xAE,0x1F}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IAppCommand2_FormatStringOffsetTable[] =

@@ -6948,7 +6996,7 @@
 

 

 /* Object interface: IAppVersion, ver. 0.0,

-   GUID={0x7b3b7a69,0x7d88,0x4847,{0xa6,0xbc,0x90,0xe2,0x46,0xa4,0x1f,0x69}} */

+   GUID={0xBCDCB538,0x01C0,0x46d1,{0xA6,0xA7,0x52,0xF4,0xD0,0x21,0xC2,0x72}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IAppVersion_FormatStringOffsetTable[] =

@@ -7022,7 +7070,7 @@
 

 

 /* Object interface: IPackage, ver. 0.0,

-   GUID={0xc853632e,0x36ca,0x4999,{0xb9,0x92,0xec,0x0d,0x40,0x8c,0xf5,0xab}} */

+   GUID={0xDCAB8386,0x4F03,0x4dbd,{0xA3,0x66,0xD9,0x0B,0xC9,0xF6,0x8D,0xE6}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IPackage_FormatStringOffsetTable[] =

@@ -7096,7 +7144,7 @@
 

 

 /* Object interface: ICurrentState, ver. 0.0,

-   GUID={0x177cae89,0x4ad6,0x42f4,{0xa4,0x58,0x00,0xec,0x33,0x89,0xe3,0xfe}} */

+   GUID={0x247954F9,0x9EDC,0x4E68,{0x8C,0xC3,0x15,0x0C,0x2B,0x89,0xEA,0xDF}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short ICurrentState_FormatStringOffsetTable[] =

@@ -7212,7 +7260,7 @@
 

 

 /* Object interface: IRegistrationUpdateHook, ver. 0.0,

-   GUID={0x3e102dc6,0x1edb,0x46a1,{0x84,0x88,0x61,0xf7,0x1b,0x35,0xed,0x5f}} */

+   GUID={0x4E223325,0xC16B,0x4eeb,{0xAE,0xDC,0x19,0xAA,0x99,0xA2,0x37,0xFA}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IRegistrationUpdateHook_FormatStringOffsetTable[] =

@@ -7280,7 +7328,7 @@
 

 

 /* Object interface: ICredentialDialog, ver. 0.0,

-   GUID={0x2603c88b,0xf971,0x4167,{0x9d,0xe1,0x87,0x1e,0xe4,0xa3,0xdc,0x84}} */

+   GUID={0xb3a47570,0x0a85,0x4aea,{0x82,0x70,0x52,0x9d,0x47,0x89,0x96,0x03}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short ICredentialDialog_FormatStringOffsetTable[] =

@@ -7330,7 +7378,7 @@
 

 

 /* Object interface: IGoogleUpdate3Web, ver. 0.0,

-   GUID={0x6dffe7fe,0x3153,0x4af1,{0x95,0xd8,0xf8,0xfc,0xca,0x97,0xe5,0x6b}} */

+   GUID={0x494B20CF,0x282E,0x4BDD,{0x9F,0x5D,0xB7,0x0C,0xB0,0x9D,0x35,0x1E}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IGoogleUpdate3Web_FormatStringOffsetTable[] =

@@ -7398,7 +7446,7 @@
 

 

 /* Object interface: IGoogleUpdate3WebSecurity, ver. 0.0,

-   GUID={0x1b9063e4,0x3882,0x485e,{0x87,0x97,0xf2,0x8a,0x02,0x40,0x78,0x2f}} */

+   GUID={0x2D363682,0x561D,0x4c3a,{0x81,0xC6,0xF2,0xF8,0x21,0x07,0x56,0x2A}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IGoogleUpdate3WebSecurity_FormatStringOffsetTable[] =

@@ -7448,7 +7496,7 @@
 

 

 /* Object interface: IAppBundleWeb, ver. 0.0,

-   GUID={0x837e40da,0xeb1b,0x440c,{0x86,0x23,0x0f,0x14,0xdf,0x15,0x8d,0xc0}} */

+   GUID={0xDD42475D,0x6D46,0x496a,{0x92,0x4E,0xBD,0x56,0x30,0xB4,0xCB,0xBA}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IAppBundleWeb_FormatStringOffsetTable[] =

@@ -7564,7 +7612,7 @@
 

 

 /* Object interface: IAppWeb, ver. 0.0,

-   GUID={0x3a49f783,0x1c7d,0x4d35,{0x8f,0x63,0x5c,0x1c,0x20,0x6b,0x9b,0x6e}} */

+   GUID={0x18D0F672,0x18B4,0x48e6,{0xAD,0x36,0x6E,0x6B,0xF0,0x1D,0xBB,0xC4}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IAppWeb_FormatStringOffsetTable[] =

@@ -7659,7 +7707,7 @@
 

 

 /* Object interface: IAppCommandWeb, ver. 0.0,

-   GUID={0x2ec826cb,0x5478,0x4533,{0x90,0x15,0x75,0x80,0xb3,0xb5,0xe0,0x3a}} */

+   GUID={0x8476CE12,0xAE1F,0x4198,{0x80,0x5C,0xBA,0x0F,0x9B,0x78,0x3F,0x57}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IAppCommandWeb_FormatStringOffsetTable[] =

@@ -7736,7 +7784,7 @@
 

 

 /* Object interface: IAppVersionWeb, ver. 0.0,

-   GUID={0x450cf5ff,0x95c4,0x4679,{0xbe,0xca,0x22,0x68,0x03,0x89,0xec,0xb9}} */

+   GUID={0x0CD01D1E,0x4A1C,0x489d,{0x93,0xB9,0x9B,0x66,0x72,0x87,0x7C,0x57}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IAppVersionWeb_FormatStringOffsetTable[] =

@@ -7810,7 +7858,7 @@
 

 

 /* Object interface: ICoCreateAsyncStatus, ver. 0.0,

-   GUID={0x9a6b447a,0x35e2,0x4f6b,{0xa8,0x7b,0x5d,0xee,0xbb,0xfd,0xad,0x17}} */

+   GUID={0x2E629606,0x312A,0x482f,{0x9B,0x12,0x2C,0x4A,0xBF,0x6F,0x0B,0x6D}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short ICoCreateAsyncStatus_FormatStringOffsetTable[] =

@@ -7884,7 +7932,7 @@
 

 

 /* Object interface: ICoCreateAsync, ver. 0.0,

-   GUID={0xc20433b3,0x0d4b,0x49f6,{0x9b,0x6c,0x6e,0xe0,0xfa,0xe0,0x78,0x37}} */

+   GUID={0xDAB1D343,0x1B2A,0x47f9,{0xB4,0x45,0x93,0xDC,0x50,0x70,0x4B,0xFE}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short ICoCreateAsync_FormatStringOffsetTable[] =

@@ -7934,7 +7982,7 @@
 

 

 /* Object interface: IBrowserHttpRequest2, ver. 0.0,

-   GUID={0xe4518371,0x7326,0x4865,{0x87,0xf8,0xd9,0xd3,0xf3,0xb2,0x87,0xa3}} */

+   GUID={0x5B25A8DC,0x1780,0x4178,{0xA6,0x29,0x6B,0xE8,0xB8,0xDE,0xFA,0xA2}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IBrowserHttpRequest2_FormatStringOffsetTable[] =

@@ -7984,7 +8032,7 @@
 

 

 /* Object interface: IProcessLauncher, ver. 0.0,

-   GUID={0xa5135e58,0x384f,0x4244,{0x9a,0x5f,0x30,0xfa,0x92,0x59,0x41,0x3c}} */

+   GUID={0x128C2DA6,0x2BC0,0x44c0,{0xB3,0xF6,0x4E,0xC2,0x2E,0x64,0x79,0x64}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IProcessLauncher_FormatStringOffsetTable[] =

@@ -8038,7 +8086,7 @@
 

 

 /* Object interface: IProcessLauncher2, ver. 0.0,

-   GUID={0xa6556dff,0xab15,0x4dc3,{0xa8,0x90,0xab,0x54,0x12,0x0b,0xea,0xec}} */

+   GUID={0xD106AB5F,0xA70E,0x400E,{0xA2,0x1B,0x96,0x20,0x8C,0x1D,0x8D,0xBB}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IProcessLauncher2_FormatStringOffsetTable[] =

@@ -8093,22 +8141,72 @@
 };

 

 

-/* Standard interface: __MIDL_itf_google_update_idl_0000_0022, ver. 0.0,

+/* Object interface: IOneClickProcessLauncher, ver. 0.0,

+   GUID={0x5CCCB0EF,0x7073,0x4516,{0x80,0x28,0x4C,0x62,0x8D,0x0C,0x8A,0xAB}} */

+

+#pragma code_seg(".orpc")

+static const unsigned short IOneClickProcessLauncher_FormatStringOffsetTable[] =

+    {

+    5034

+    };

+

+static const MIDL_STUBLESS_PROXY_INFO IOneClickProcessLauncher_ProxyInfo =

+    {

+    &Object_StubDesc,

+    google_update_idl__MIDL_ProcFormatString.Format,

+    &IOneClickProcessLauncher_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0

+    };

+

+

+static const MIDL_SERVER_INFO IOneClickProcessLauncher_ServerInfo = 

+    {

+    &Object_StubDesc,

+    0,

+    google_update_idl__MIDL_ProcFormatString.Format,

+    &IOneClickProcessLauncher_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0,

+    0};

+CINTERFACE_PROXY_VTABLE(4) _IOneClickProcessLauncherProxyVtbl = 

+{

+    &IOneClickProcessLauncher_ProxyInfo,

+    &IID_IOneClickProcessLauncher,

+    IUnknown_QueryInterface_Proxy,

+    IUnknown_AddRef_Proxy,

+    IUnknown_Release_Proxy ,

+    (void *) (INT_PTR) -1 /* IOneClickProcessLauncher::LaunchAppCommand */

+};

+

+const CInterfaceStubVtbl _IOneClickProcessLauncherStubVtbl =

+{

+    &IID_IOneClickProcessLauncher,

+    &IOneClickProcessLauncher_ServerInfo,

+    4,

+    0, /* pure interpreted */

+    CStdStubBuffer_METHODS

+};

+

+

+/* Standard interface: __MIDL_itf_google_update_idl_0000_0023, ver. 0.0,

    GUID={0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} */

 

 

 /* Object interface: IProgressWndEvents, ver. 0.0,

-   GUID={0xe55b90f1,0xda33,0x400b,{0xb0,0x9e,0x3a,0xff,0x7d,0x46,0xbd,0x83}} */

+   GUID={0x1C642CED,0xCA3B,0x4013,{0xA9,0xDF,0xCA,0x6C,0xE5,0xFF,0x65,0x03}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IProgressWndEvents_FormatStringOffsetTable[] =

     {

-    5034,

-    5068,

-    5102,

-    5136,

-    5170,

-    5204

+    5082,

+    5116,

+    5150,

+    5184,

+    5218,

+    5252

     };

 

 static const MIDL_STUBLESS_PROXY_INFO IProgressWndEvents_ProxyInfo =

@@ -8158,21 +8256,21 @@
 

 

 /* Object interface: IJobObserver, ver. 0.0,

-   GUID={0x99f8e195,0x1042,0x4f89,{0xa2,0x8c,0x89,0xcd,0xb7,0x4a,0x14,0xae}} */

+   GUID={0x49D7563B,0x2DDB,0x4831,{0x88,0xC8,0x76,0x8A,0x53,0x83,0x38,0x37}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IJobObserver_FormatStringOffsetTable[] =

     {

-    5034,

-    5068,

-    5246,

-    5136,

-    5288,

+    5082,

+    5116,

+    5294,

+    5184,

     5336,

+    5384,

     4036,

-    5370,

-    5404,

-    5452

+    5418,

+    5452,

+    5500

     };

 

 static const MIDL_STUBLESS_PROXY_INFO IJobObserver_ProxyInfo =

@@ -8226,12 +8324,12 @@
 

 

 /* Object interface: IJobObserver2, ver. 0.0,

-   GUID={0xd9aa3288,0x4ea7,0x4e67,{0xae,0x60,0xd1,0x8e,0xad,0xcb,0x92,0x3d}} */

+   GUID={0x19692F10,0xADD2,0x4EFF,{0xBE,0x54,0xE6,0x1C,0x62,0xE4,0x0D,0x13}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IJobObserver2_FormatStringOffsetTable[] =

     {

-    5494

+    5542

     };

 

 static const MIDL_STUBLESS_PROXY_INFO IJobObserver2_ProxyInfo =

@@ -8276,13 +8374,13 @@
 

 

 /* Object interface: IGoogleUpdate, ver. 0.0,

-   GUID={0x79e0c401,0xb7bc,0x4de5,{0x81,0x04,0x71,0x35,0x0f,0x3a,0x9b,0x67}} */

+   GUID={0x31AC3F11,0xE5EA,0x4a85,{0x8A,0x3D,0x8E,0x09,0x5A,0x39,0xC2,0x7B}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IGoogleUpdate_FormatStringOffsetTable[] =

     {

-    5542,

-    5590

+    5590,

+    5638

     };

 

 static const MIDL_STUBLESS_PROXY_INFO IGoogleUpdate_ProxyInfo =

@@ -8328,12 +8426,12 @@
 

 

 /* Object interface: IGoogleUpdateCore, ver. 0.0,

-   GUID={0xfce48f77,0xc677,0x4012,{0x8a,0x1a,0x54,0xd2,0xe2,0xbc,0x07,0xbd}} */

+   GUID={0x909489C2,0x85A6,0x4322,{0xAA,0x56,0xD2,0x52,0x78,0x64,0x9D,0x67}} */

 

 #pragma code_seg(".orpc")

 static const unsigned short IGoogleUpdateCore_FormatStringOffsetTable[] =

     {

-    5638

+    5686

     };

 

 static const MIDL_STUBLESS_PROXY_INFO IGoogleUpdateCore_ProxyInfo =

@@ -8402,106 +8500,110 @@
 

 const CInterfaceProxyVtbl * const _google_update_idl_ProxyVtblList[] = 

 {

-    ( CInterfaceProxyVtbl *) &_IGoogleUpdateProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IPackageProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IApp2ProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IProcessLauncherProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IAppCommand2ProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IAppVersionProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IBrowserHttpRequest2ProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IGoogleUpdateCoreProxyVtbl,

     ( CInterfaceProxyVtbl *) &_ICoCreateAsyncStatusProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IAppBundleProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IAppWebProxyVtbl,

     ( CInterfaceProxyVtbl *) &_IJobObserver2ProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_ICurrentStateProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_ICredentialDialogProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IJobObserverProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IAppProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_ICoCreateAsyncProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IAppCommandProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IRegistrationUpdateHookProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IGoogleUpdateProxyVtbl,

     ( CInterfaceProxyVtbl *) &_IAppCommandWebProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IAppVersionWebProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IRegistrationUpdateHookProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IAppVersionProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IJobObserverProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_ICoCreateAsyncProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IAppCommand2ProxyVtbl,

     ( CInterfaceProxyVtbl *) &_IGoogleUpdate3ProxyVtbl,

     ( CInterfaceProxyVtbl *) &_IAppBundleWebProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IGoogleUpdate3WebSecurityProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IProgressWndEventsProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IGoogleUpdate3WebProxyVtbl,

     ( CInterfaceProxyVtbl *) &_IProcessLauncher2ProxyVtbl,

-    ( CInterfaceProxyVtbl *) &_IAppVersionWebProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_ICredentialDialogProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IAppWebProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IGoogleUpdate3WebSecurityProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IPackageProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IAppProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IProcessLauncherProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IApp2ProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IGoogleUpdateCoreProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IGoogleUpdate3WebProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IBrowserHttpRequest2ProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IAppBundleProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IProgressWndEventsProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IOneClickProcessLauncherProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_ICurrentStateProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IAppCommandProxyVtbl,

     0

 };

 

 const CInterfaceStubVtbl * const _google_update_idl_StubVtblList[] = 

 {

-    ( CInterfaceStubVtbl *) &_IGoogleUpdateStubVtbl,

-    ( CInterfaceStubVtbl *) &_IPackageStubVtbl,

-    ( CInterfaceStubVtbl *) &_IApp2StubVtbl,

-    ( CInterfaceStubVtbl *) &_IProcessLauncherStubVtbl,

-    ( CInterfaceStubVtbl *) &_IAppCommand2StubVtbl,

-    ( CInterfaceStubVtbl *) &_IAppVersionStubVtbl,

-    ( CInterfaceStubVtbl *) &_IBrowserHttpRequest2StubVtbl,

-    ( CInterfaceStubVtbl *) &_IGoogleUpdateCoreStubVtbl,

     ( CInterfaceStubVtbl *) &_ICoCreateAsyncStatusStubVtbl,

-    ( CInterfaceStubVtbl *) &_IAppBundleStubVtbl,

-    ( CInterfaceStubVtbl *) &_IAppWebStubVtbl,

     ( CInterfaceStubVtbl *) &_IJobObserver2StubVtbl,

-    ( CInterfaceStubVtbl *) &_ICurrentStateStubVtbl,

-    ( CInterfaceStubVtbl *) &_ICredentialDialogStubVtbl,

-    ( CInterfaceStubVtbl *) &_IJobObserverStubVtbl,

-    ( CInterfaceStubVtbl *) &_IAppStubVtbl,

-    ( CInterfaceStubVtbl *) &_ICoCreateAsyncStubVtbl,

-    ( CInterfaceStubVtbl *) &_IAppCommandStubVtbl,

-    ( CInterfaceStubVtbl *) &_IRegistrationUpdateHookStubVtbl,

+    ( CInterfaceStubVtbl *) &_IGoogleUpdateStubVtbl,

     ( CInterfaceStubVtbl *) &_IAppCommandWebStubVtbl,

+    ( CInterfaceStubVtbl *) &_IAppVersionWebStubVtbl,

+    ( CInterfaceStubVtbl *) &_IRegistrationUpdateHookStubVtbl,

+    ( CInterfaceStubVtbl *) &_IAppVersionStubVtbl,

+    ( CInterfaceStubVtbl *) &_IJobObserverStubVtbl,

+    ( CInterfaceStubVtbl *) &_ICoCreateAsyncStubVtbl,

+    ( CInterfaceStubVtbl *) &_IAppCommand2StubVtbl,

     ( CInterfaceStubVtbl *) &_IGoogleUpdate3StubVtbl,

     ( CInterfaceStubVtbl *) &_IAppBundleWebStubVtbl,

-    ( CInterfaceStubVtbl *) &_IGoogleUpdate3WebSecurityStubVtbl,

-    ( CInterfaceStubVtbl *) &_IProgressWndEventsStubVtbl,

-    ( CInterfaceStubVtbl *) &_IGoogleUpdate3WebStubVtbl,

     ( CInterfaceStubVtbl *) &_IProcessLauncher2StubVtbl,

-    ( CInterfaceStubVtbl *) &_IAppVersionWebStubVtbl,

+    ( CInterfaceStubVtbl *) &_ICredentialDialogStubVtbl,

+    ( CInterfaceStubVtbl *) &_IAppWebStubVtbl,

+    ( CInterfaceStubVtbl *) &_IGoogleUpdate3WebSecurityStubVtbl,

+    ( CInterfaceStubVtbl *) &_IPackageStubVtbl,

+    ( CInterfaceStubVtbl *) &_IAppStubVtbl,

+    ( CInterfaceStubVtbl *) &_IProcessLauncherStubVtbl,

+    ( CInterfaceStubVtbl *) &_IApp2StubVtbl,

+    ( CInterfaceStubVtbl *) &_IGoogleUpdateCoreStubVtbl,

+    ( CInterfaceStubVtbl *) &_IGoogleUpdate3WebStubVtbl,

+    ( CInterfaceStubVtbl *) &_IBrowserHttpRequest2StubVtbl,

+    ( CInterfaceStubVtbl *) &_IAppBundleStubVtbl,

+    ( CInterfaceStubVtbl *) &_IProgressWndEventsStubVtbl,

+    ( CInterfaceStubVtbl *) &_IOneClickProcessLauncherStubVtbl,

+    ( CInterfaceStubVtbl *) &_ICurrentStateStubVtbl,

+    ( CInterfaceStubVtbl *) &_IAppCommandStubVtbl,

     0

 };

 

 PCInterfaceName const _google_update_idl_InterfaceNamesList[] = 

 {

-    "IGoogleUpdate",

-    "IPackage",

-    "IApp2",

-    "IProcessLauncher",

-    "IAppCommand2",

-    "IAppVersion",

-    "IBrowserHttpRequest2",

-    "IGoogleUpdateCore",

     "ICoCreateAsyncStatus",

-    "IAppBundle",

-    "IAppWeb",

     "IJobObserver2",

-    "ICurrentState",

-    "ICredentialDialog",

-    "IJobObserver",

-    "IApp",

-    "ICoCreateAsync",

-    "IAppCommand",

-    "IRegistrationUpdateHook",

+    "IGoogleUpdate",

     "IAppCommandWeb",

+    "IAppVersionWeb",

+    "IRegistrationUpdateHook",

+    "IAppVersion",

+    "IJobObserver",

+    "ICoCreateAsync",

+    "IAppCommand2",

     "IGoogleUpdate3",

     "IAppBundleWeb",

-    "IGoogleUpdate3WebSecurity",

-    "IProgressWndEvents",

-    "IGoogleUpdate3Web",

     "IProcessLauncher2",

-    "IAppVersionWeb",

+    "ICredentialDialog",

+    "IAppWeb",

+    "IGoogleUpdate3WebSecurity",

+    "IPackage",

+    "IApp",

+    "IProcessLauncher",

+    "IApp2",

+    "IGoogleUpdateCore",

+    "IGoogleUpdate3Web",

+    "IBrowserHttpRequest2",

+    "IAppBundle",

+    "IProgressWndEvents",

+    "IOneClickProcessLauncher",

+    "ICurrentState",

+    "IAppCommand",

     0

 };

 

 const IID *  const _google_update_idl_BaseIIDList[] = 

 {

+    &IID_IDispatch,

+    0,

     0,

     &IID_IDispatch,

     &IID_IDispatch,

-    0,

     &IID_IDispatch,

     &IID_IDispatch,

     0,

@@ -8510,20 +8612,20 @@
     &IID_IDispatch,

     &IID_IDispatch,

     0,

-    &IID_IDispatch,

-    0,

     0,

     &IID_IDispatch,

     0,

     &IID_IDispatch,

     &IID_IDispatch,

+    0,

     &IID_IDispatch,

+    0,

     &IID_IDispatch,

+    0,

     &IID_IDispatch,

     0,

     0,

     &IID_IDispatch,

-    0,

     &IID_IDispatch,

     0

 };

@@ -8535,12 +8637,12 @@
 {

     IID_BS_LOOKUP_SETUP

 

-    IID_BS_LOOKUP_INITIAL_TEST( _google_update_idl, 27, 16 )

+    IID_BS_LOOKUP_INITIAL_TEST( _google_update_idl, 28, 16 )

     IID_BS_LOOKUP_NEXT_TEST( _google_update_idl, 8 )

     IID_BS_LOOKUP_NEXT_TEST( _google_update_idl, 4 )

     IID_BS_LOOKUP_NEXT_TEST( _google_update_idl, 2 )

     IID_BS_LOOKUP_NEXT_TEST( _google_update_idl, 1 )

-    IID_BS_LOOKUP_RETURN_RESULT( _google_update_idl, 27, *pIndex )

+    IID_BS_LOOKUP_RETURN_RESULT( _google_update_idl, 28, *pIndex )

     

 }

 

@@ -8551,7 +8653,7 @@
     (const PCInterfaceName * ) & _google_update_idl_InterfaceNamesList,

     (const IID ** ) & _google_update_idl_BaseIIDList,

     & _google_update_idl_IID_Lookup, 

-    27,

+    28,

     2,

     0, /* table of [async_uuid] interfaces */

     0, /* Filler1 */

diff --git a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.dlldata.c b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.dlldata.c
new file mode 100644
index 0000000..aa1c55c
--- /dev/null
+++ b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.dlldata.c
@@ -0,0 +1,37 @@
+/*********************************************************

+   DllData file -- generated by MIDL compiler 

+

+        DO NOT ALTER THIS FILE

+

+   This file is regenerated by MIDL on every IDL file compile.

+

+   To completely reconstruct this file, delete it and rerun MIDL

+   on all the IDL files in this DLL, specifying this file for the

+   /dlldata command line option

+

+*********************************************************/

+

+

+#include <rpcproxy.h>

+

+#ifdef __cplusplus

+extern "C"   {

+#endif

+

+EXTERN_PROXY_FILE( chromoting_lib )

+

+

+PROXYFILE_LIST_START

+/* Start of list */

+  REFERENCE_PROXY_FILE( chromoting_lib ),

+/* End of list */

+PROXYFILE_LIST_END

+

+

+DLLDATA_ROUTINES( aProxyFileList, GET_DLL_CLSID )

+

+#ifdef __cplusplus

+}  /*extern "C" */

+#endif

+

+/* end of generated dlldata file */

diff --git a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.h b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.h
new file mode 100644
index 0000000..d498cf6
--- /dev/null
+++ b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.h
@@ -0,0 +1,327 @@
+

+

+/* this ALWAYS GENERATED file contains the definitions for the interfaces */

+

+

+ /* File created by MIDL compiler version 8.xx.xxxx */

+/* at a redacted point in time

+ */

+/* Compiler settings for gen/remoting/host/win/chromoting_lib.idl:

+    Oicf, W1, Zp8, env=Win64 (32b run), target_arch=ARM64 8.01.0622 

+    protocol : dce , ms_ext, c_ext, robust

+    error checks: allocation ref bounds_check enum stub_data 

+    VC __declspec() decoration level: 

+         __declspec(uuid()), __declspec(selectany), __declspec(novtable)

+         DECLSPEC_UUID(), MIDL_INTERFACE()

+*/

+/* @@MIDL_FILE_HEADING(  ) */

+

+#pragma warning( disable: 4049 )  /* more than 64k source lines */

+

+

+/* verify that the <rpcndr.h> version is high enough to compile this file*/

+#ifndef __REQUIRED_RPCNDR_H_VERSION__

+#define __REQUIRED_RPCNDR_H_VERSION__ 475

+#endif

+

+#include "rpc.h"

+#include "rpcndr.h"

+

+#ifndef __RPCNDR_H_VERSION__

+#error this stub requires an updated version of <rpcndr.h>

+#endif /* __RPCNDR_H_VERSION__ */

+

+#ifndef COM_NO_WINDOWS_H

+#include "windows.h"

+#include "ole2.h"

+#endif /*COM_NO_WINDOWS_H*/

+

+#ifndef __chromoting_lib_h__

+#define __chromoting_lib_h__

+

+#if defined(_MSC_VER) && (_MSC_VER >= 1020)

+#pragma once

+#endif

+

+/* Forward Declarations */ 

+

+#ifndef __IRdpDesktopSessionEventHandler_FWD_DEFINED__

+#define __IRdpDesktopSessionEventHandler_FWD_DEFINED__

+typedef interface IRdpDesktopSessionEventHandler IRdpDesktopSessionEventHandler;

+

+#endif 	/* __IRdpDesktopSessionEventHandler_FWD_DEFINED__ */

+

+

+#ifndef __IRdpDesktopSession_FWD_DEFINED__

+#define __IRdpDesktopSession_FWD_DEFINED__

+typedef interface IRdpDesktopSession IRdpDesktopSession;

+

+#endif 	/* __IRdpDesktopSession_FWD_DEFINED__ */

+

+

+#ifndef __RdpDesktopSession_FWD_DEFINED__

+#define __RdpDesktopSession_FWD_DEFINED__

+

+#ifdef __cplusplus

+typedef class RdpDesktopSession RdpDesktopSession;

+#else

+typedef struct RdpDesktopSession RdpDesktopSession;

+#endif /* __cplusplus */

+

+#endif 	/* __RdpDesktopSession_FWD_DEFINED__ */

+

+

+/* header files for imported files */

+#include "oaidl.h"

+#include "ocidl.h"

+

+#ifdef __cplusplus

+extern "C"{

+#endif 

+

+

+#ifndef __IRdpDesktopSessionEventHandler_INTERFACE_DEFINED__

+#define __IRdpDesktopSessionEventHandler_INTERFACE_DEFINED__

+

+/* interface IRdpDesktopSessionEventHandler */

+/* [unique][helpstring][nonextensible][uuid][object] */ 

+

+

+EXTERN_C const IID IID_IRdpDesktopSessionEventHandler;

+

+#if defined(__cplusplus) && !defined(CINTERFACE)

+    

+    MIDL_INTERFACE("b59b96da-83cb-40ee-9b91-c377400fc3e3")

+    IRdpDesktopSessionEventHandler : public IUnknown

+    {

+    public:

+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OnRdpConnected( void) = 0;

+        

+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OnRdpClosed( void) = 0;

+        

+    };

+    

+    

+#else 	/* C style interface */

+

+    typedef struct IRdpDesktopSessionEventHandlerVtbl

+    {

+        BEGIN_INTERFACE

+        

+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 

+            IRdpDesktopSessionEventHandler * This,

+            /* [in] */ REFIID riid,

+            /* [annotation][iid_is][out] */ 

+            _COM_Outptr_  void **ppvObject);

+        

+        ULONG ( STDMETHODCALLTYPE *AddRef )( 

+            IRdpDesktopSessionEventHandler * This);

+        

+        ULONG ( STDMETHODCALLTYPE *Release )( 

+            IRdpDesktopSessionEventHandler * This);

+        

+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *OnRdpConnected )( 

+            IRdpDesktopSessionEventHandler * This);

+        

+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *OnRdpClosed )( 

+            IRdpDesktopSessionEventHandler * This);

+        

+        END_INTERFACE

+    } IRdpDesktopSessionEventHandlerVtbl;

+

+    interface IRdpDesktopSessionEventHandler

+    {

+        CONST_VTBL struct IRdpDesktopSessionEventHandlerVtbl *lpVtbl;

+    };

+

+    

+

+#ifdef COBJMACROS

+

+

+#define IRdpDesktopSessionEventHandler_QueryInterface(This,riid,ppvObject)	\

+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 

+

+#define IRdpDesktopSessionEventHandler_AddRef(This)	\

+    ( (This)->lpVtbl -> AddRef(This) ) 

+

+#define IRdpDesktopSessionEventHandler_Release(This)	\

+    ( (This)->lpVtbl -> Release(This) ) 

+

+

+#define IRdpDesktopSessionEventHandler_OnRdpConnected(This)	\

+    ( (This)->lpVtbl -> OnRdpConnected(This) ) 

+

+#define IRdpDesktopSessionEventHandler_OnRdpClosed(This)	\

+    ( (This)->lpVtbl -> OnRdpClosed(This) ) 

+

+#endif /* COBJMACROS */

+

+

+#endif 	/* C style interface */

+

+

+

+

+#endif 	/* __IRdpDesktopSessionEventHandler_INTERFACE_DEFINED__ */

+

+

+#ifndef __IRdpDesktopSession_INTERFACE_DEFINED__

+#define __IRdpDesktopSession_INTERFACE_DEFINED__

+

+/* interface IRdpDesktopSession */

+/* [unique][helpstring][nonextensible][uuid][object] */ 

+

+

+EXTERN_C const IID IID_IRdpDesktopSession;

+

+#if defined(__cplusplus) && !defined(CINTERFACE)

+    

+    MIDL_INTERFACE("6a7699f0-ee43-43e7-aa30-a6738f9bd470")

+    IRdpDesktopSession : public IUnknown

+    {

+    public:

+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Connect( 

+            /* [in] */ long width,

+            /* [in] */ long height,

+            /* [in] */ long dpi_x,

+            /* [in] */ long dpi_y,

+            /* [in] */ BSTR terminal_id,

+            /* [in] */ DWORD port_number,

+            /* [in] */ IRdpDesktopSessionEventHandler *event_handler) = 0;

+        

+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Disconnect( void) = 0;

+        

+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE ChangeResolution( 

+            /* [in] */ long width,

+            /* [in] */ long height,

+            /* [in] */ long dpi_x,

+            /* [in] */ long dpi_y) = 0;

+        

+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE InjectSas( void) = 0;

+        

+    };

+    

+    

+#else 	/* C style interface */

+

+    typedef struct IRdpDesktopSessionVtbl

+    {

+        BEGIN_INTERFACE

+        

+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 

+            IRdpDesktopSession * This,

+            /* [in] */ REFIID riid,

+            /* [annotation][iid_is][out] */ 

+            _COM_Outptr_  void **ppvObject);

+        

+        ULONG ( STDMETHODCALLTYPE *AddRef )( 

+            IRdpDesktopSession * This);

+        

+        ULONG ( STDMETHODCALLTYPE *Release )( 

+            IRdpDesktopSession * This);

+        

+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Connect )( 

+            IRdpDesktopSession * This,

+            /* [in] */ long width,

+            /* [in] */ long height,

+            /* [in] */ long dpi_x,

+            /* [in] */ long dpi_y,

+            /* [in] */ BSTR terminal_id,

+            /* [in] */ DWORD port_number,

+            /* [in] */ IRdpDesktopSessionEventHandler *event_handler);

+        

+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Disconnect )( 

+            IRdpDesktopSession * This);

+        

+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *ChangeResolution )( 

+            IRdpDesktopSession * This,

+            /* [in] */ long width,

+            /* [in] */ long height,

+            /* [in] */ long dpi_x,

+            /* [in] */ long dpi_y);

+        

+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *InjectSas )( 

+            IRdpDesktopSession * This);

+        

+        END_INTERFACE

+    } IRdpDesktopSessionVtbl;

+

+    interface IRdpDesktopSession

+    {

+        CONST_VTBL struct IRdpDesktopSessionVtbl *lpVtbl;

+    };

+

+    

+

+#ifdef COBJMACROS

+

+

+#define IRdpDesktopSession_QueryInterface(This,riid,ppvObject)	\

+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) 

+

+#define IRdpDesktopSession_AddRef(This)	\

+    ( (This)->lpVtbl -> AddRef(This) ) 

+

+#define IRdpDesktopSession_Release(This)	\

+    ( (This)->lpVtbl -> Release(This) ) 

+

+

+#define IRdpDesktopSession_Connect(This,width,height,dpi_x,dpi_y,terminal_id,port_number,event_handler)	\

+    ( (This)->lpVtbl -> Connect(This,width,height,dpi_x,dpi_y,terminal_id,port_number,event_handler) ) 

+

+#define IRdpDesktopSession_Disconnect(This)	\

+    ( (This)->lpVtbl -> Disconnect(This) ) 

+

+#define IRdpDesktopSession_ChangeResolution(This,width,height,dpi_x,dpi_y)	\

+    ( (This)->lpVtbl -> ChangeResolution(This,width,height,dpi_x,dpi_y) ) 

+

+#define IRdpDesktopSession_InjectSas(This)	\

+    ( (This)->lpVtbl -> InjectSas(This) ) 

+

+#endif /* COBJMACROS */

+

+

+#endif 	/* C style interface */

+

+

+

+

+#endif 	/* __IRdpDesktopSession_INTERFACE_DEFINED__ */

+

+

+

+#ifndef __ChromotingLib_LIBRARY_DEFINED__

+#define __ChromotingLib_LIBRARY_DEFINED__

+

+/* library ChromotingLib */

+/* [helpstring][version][uuid] */ 

+

+

+EXTERN_C const IID LIBID_ChromotingLib;

+

+EXTERN_C const CLSID CLSID_RdpDesktopSession;

+

+#ifdef __cplusplus

+

+class DECLSPEC_UUID("7bf898db-ce6c-57a3-a473-3aa21bf8c4c4")

+RdpDesktopSession;

+#endif

+#endif /* __ChromotingLib_LIBRARY_DEFINED__ */

+

+/* Additional Prototypes for ALL interfaces */

+

+unsigned long             __RPC_USER  BSTR_UserSize(     unsigned long *, unsigned long            , BSTR * ); 

+unsigned char * __RPC_USER  BSTR_UserMarshal(  unsigned long *, unsigned char *, BSTR * ); 

+unsigned char * __RPC_USER  BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * ); 

+void                      __RPC_USER  BSTR_UserFree(     unsigned long *, BSTR * ); 

+

+/* end of Additional Prototypes */

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif

+

+

diff --git a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.tlb b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.tlb
new file mode 100644
index 0000000..0a7f3139
--- /dev/null
+++ b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib.tlb
Binary files differ
diff --git a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib_i.c b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib_i.c
new file mode 100644
index 0000000..7172c90
--- /dev/null
+++ b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib_i.c
@@ -0,0 +1,88 @@
+

+

+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */

+

+/* link this file in with the server and any clients */

+

+

+ /* File created by MIDL compiler version 8.xx.xxxx */

+/* at a redacted point in time

+ */

+/* Compiler settings for gen/remoting/host/win/chromoting_lib.idl:

+    Oicf, W1, Zp8, env=Win64 (32b run), target_arch=ARM64 8.01.0622 

+    protocol : dce , ms_ext, c_ext, robust

+    error checks: allocation ref bounds_check enum stub_data 

+    VC __declspec() decoration level: 

+         __declspec(uuid()), __declspec(selectany), __declspec(novtable)

+         DECLSPEC_UUID(), MIDL_INTERFACE()

+*/

+/* @@MIDL_FILE_HEADING(  ) */

+

+#pragma warning( disable: 4049 )  /* more than 64k source lines */

+

+

+#ifdef __cplusplus

+extern "C"{

+#endif 

+

+

+#include <rpc.h>

+#include <rpcndr.h>

+

+#ifdef _MIDL_USE_GUIDDEF_

+

+#ifndef INITGUID

+#define INITGUID

+#include <guiddef.h>

+#undef INITGUID

+#else

+#include <guiddef.h>

+#endif

+

+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \

+        DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)

+

+#else // !_MIDL_USE_GUIDDEF_

+

+#ifndef __IID_DEFINED__

+#define __IID_DEFINED__

+

+typedef struct _IID

+{

+    unsigned long x;

+    unsigned short s1;

+    unsigned short s2;

+    unsigned char  c[8];

+} IID;

+

+#endif // __IID_DEFINED__

+

+#ifndef CLSID_DEFINED

+#define CLSID_DEFINED

+typedef IID CLSID;

+#endif // CLSID_DEFINED

+

+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \

+        EXTERN_C __declspec(selectany) const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}

+

+#endif // !_MIDL_USE_GUIDDEF_

+

+MIDL_DEFINE_GUID(IID, IID_IRdpDesktopSessionEventHandler,0xb59b96da,0x83cb,0x40ee,0x9b,0x91,0xc3,0x77,0x40,0x0f,0xc3,0xe3);

+

+

+MIDL_DEFINE_GUID(IID, IID_IRdpDesktopSession,0x6a7699f0,0xee43,0x43e7,0xaa,0x30,0xa6,0x73,0x8f,0x9b,0xd4,0x70);

+

+

+MIDL_DEFINE_GUID(IID, LIBID_ChromotingLib,0xb6396c45,0xb0cc,0x456b,0x9f,0x49,0xf1,0x29,0x64,0xee,0x6d,0xf4);

+

+

+MIDL_DEFINE_GUID(CLSID, CLSID_RdpDesktopSession,0x7bf898db,0xce6c,0x57a3,0xa4,0x73,0x3a,0xa2,0x1b,0xf8,0xc4,0xc4);

+

+#undef MIDL_DEFINE_GUID

+

+#ifdef __cplusplus

+}

+#endif

+

+

+

diff --git a/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib_p.c b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib_p.c
new file mode 100644
index 0000000..a8463c0
--- /dev/null
+++ b/third_party/win_build_output/midl/remoting/host/win/arm64/chromoting_lib_p.c
@@ -0,0 +1,594 @@
+

+

+/* this ALWAYS GENERATED file contains the proxy stub code */

+

+

+ /* File created by MIDL compiler version 8.xx.xxxx */

+/* at a redacted point in time

+ */

+/* Compiler settings for gen/remoting/host/win/chromoting_lib.idl:

+    Oicf, W1, Zp8, env=Win64 (32b run), target_arch=ARM64 8.01.0622 

+    protocol : dce , ms_ext, c_ext, robust

+    error checks: allocation ref bounds_check enum stub_data 

+    VC __declspec() decoration level: 

+         __declspec(uuid()), __declspec(selectany), __declspec(novtable)

+         DECLSPEC_UUID(), MIDL_INTERFACE()

+*/

+/* @@MIDL_FILE_HEADING(  ) */

+

+#if defined(_M_ARM64)

+

+

+#pragma warning( disable: 4049 )  /* more than 64k source lines */

+#if _MSC_VER >= 1200

+#pragma warning(push)

+#endif

+

+#pragma warning( disable: 4211 )  /* redefine extern to static */

+#pragma warning( disable: 4232 )  /* dllimport identity*/

+#pragma warning( disable: 4024 )  /* array to pointer mapping*/

+#pragma warning( disable: 4152 )  /* function/data pointer conversion in expression */

+

+#define USE_STUBLESS_PROXY

+

+

+/* verify that the <rpcproxy.h> version is high enough to compile this file*/

+#ifndef __REDQ_RPCPROXY_H_VERSION__

+#define __REQUIRED_RPCPROXY_H_VERSION__ 475

+#endif

+

+

+#include "rpcproxy.h"

+#ifndef __RPCPROXY_H_VERSION__

+#error this stub requires an updated version of <rpcproxy.h>

+#endif /* __RPCPROXY_H_VERSION__ */

+

+

+#include "chromoting_lib.h"

+

+#define TYPE_FORMAT_STRING_SIZE   57                                

+#define PROC_FORMAT_STRING_SIZE   249                               

+#define EXPR_FORMAT_STRING_SIZE   1                                 

+#define TRANSMIT_AS_TABLE_SIZE    0            

+#define WIRE_MARSHAL_TABLE_SIZE   1            

+

+typedef struct _chromoting_lib_MIDL_TYPE_FORMAT_STRING

+    {

+    short          Pad;

+    unsigned char  Format[ TYPE_FORMAT_STRING_SIZE ];

+    } chromoting_lib_MIDL_TYPE_FORMAT_STRING;

+

+typedef struct _chromoting_lib_MIDL_PROC_FORMAT_STRING

+    {

+    short          Pad;

+    unsigned char  Format[ PROC_FORMAT_STRING_SIZE ];

+    } chromoting_lib_MIDL_PROC_FORMAT_STRING;

+

+typedef struct _chromoting_lib_MIDL_EXPR_FORMAT_STRING

+    {

+    long          Pad;

+    unsigned char  Format[ EXPR_FORMAT_STRING_SIZE ];

+    } chromoting_lib_MIDL_EXPR_FORMAT_STRING;

+

+

+static const RPC_SYNTAX_IDENTIFIER  _RpcTransferSyntax = 

+{{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}};

+

+

+extern const chromoting_lib_MIDL_TYPE_FORMAT_STRING chromoting_lib__MIDL_TypeFormatString;

+extern const chromoting_lib_MIDL_PROC_FORMAT_STRING chromoting_lib__MIDL_ProcFormatString;

+extern const chromoting_lib_MIDL_EXPR_FORMAT_STRING chromoting_lib__MIDL_ExprFormatString;

+

+

+extern const MIDL_STUB_DESC Object_StubDesc;

+

+

+extern const MIDL_SERVER_INFO IRdpDesktopSessionEventHandler_ServerInfo;

+extern const MIDL_STUBLESS_PROXY_INFO IRdpDesktopSessionEventHandler_ProxyInfo;

+

+

+extern const MIDL_STUB_DESC Object_StubDesc;

+

+

+extern const MIDL_SERVER_INFO IRdpDesktopSession_ServerInfo;

+extern const MIDL_STUBLESS_PROXY_INFO IRdpDesktopSession_ProxyInfo;

+

+

+extern const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[ WIRE_MARSHAL_TABLE_SIZE ];

+

+#if !defined(__RPC_ARM64__)

+#error  Invalid build platform for this stub.

+#endif

+

+static const chromoting_lib_MIDL_PROC_FORMAT_STRING chromoting_lib__MIDL_ProcFormatString =

+    {

+        0,

+        {

+

+	/* Procedure OnRdpConnected */

+

+			0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/*  2 */	NdrFcLong( 0x0 ),	/* 0 */

+/*  6 */	NdrFcShort( 0x3 ),	/* 3 */

+/*  8 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 10 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 12 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 14 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+			0x1,		/* 1 */

+/* 16 */	0xc,		/* 12 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 18 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 20 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 22 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 24 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 26 */	0x1,		/* 1 */

+			0x80,		/* 128 */

+

+	/* Return value */

+

+/* 28 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 30 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 32 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure Disconnect */

+

+

+	/* Procedure OnRdpClosed */

+

+/* 34 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 36 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 40 */	NdrFcShort( 0x4 ),	/* 4 */

+/* 42 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 44 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 46 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 48 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+			0x1,		/* 1 */

+/* 50 */	0xc,		/* 12 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 52 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 54 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 56 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 58 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 60 */	0x1,		/* 1 */

+			0x80,		/* 128 */

+

+	/* Return value */

+

+

+	/* Return value */

+

+/* 62 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 64 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 66 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure Connect */

+

+/* 68 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 70 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 74 */	NdrFcShort( 0x3 ),	/* 3 */

+/* 76 */	NdrFcShort( 0x48 ),	/* ARM64 Stack size/offset = 72 */

+/* 78 */	NdrFcShort( 0x28 ),	/* 40 */

+/* 80 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 82 */	0x46,		/* Oi2 Flags:  clt must size, has return, has ext, */

+			0x8,		/* 8 */

+/* 84 */	0x14,		/* 20 */

+			0x5,		/* Ext Flags:  new corr desc, srv corr check, */

+/* 86 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 88 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 90 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 92 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 94 */	0x8,		/* 8 */

+			0x80,		/* 128 */

+/* 96 */	0x81,		/* 129 */

+			0x82,		/* 130 */

+/* 98 */	0x83,		/* 131 */

+			0x84,		/* 132 */

+/* 100 */	0x85,		/* 133 */

+			0x86,		/* 134 */

+/* 102 */	0x87,		/* 135 */

+			0x0,		/* 0 */

+

+	/* Parameter width */

+

+/* 104 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 106 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 108 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter height */

+

+/* 110 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 112 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 114 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter dpi_x */

+

+/* 116 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 118 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 120 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter dpi_y */

+

+/* 122 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 124 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

+/* 126 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter terminal_id */

+

+/* 128 */	NdrFcShort( 0x8b ),	/* Flags:  must size, must free, in, by val, */

+/* 130 */	NdrFcShort( 0x28 ),	/* ARM64 Stack size/offset = 40 */

+/* 132 */	NdrFcShort( 0x1c ),	/* Type Offset=28 */

+

+	/* Parameter port_number */

+

+/* 134 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 136 */	NdrFcShort( 0x30 ),	/* ARM64 Stack size/offset = 48 */

+/* 138 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter event_handler */

+

+/* 140 */	NdrFcShort( 0xb ),	/* Flags:  must size, must free, in, */

+/* 142 */	NdrFcShort( 0x38 ),	/* ARM64 Stack size/offset = 56 */

+/* 144 */	NdrFcShort( 0x26 ),	/* Type Offset=38 */

+

+	/* Return value */

+

+/* 146 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 148 */	NdrFcShort( 0x40 ),	/* ARM64 Stack size/offset = 64 */

+/* 150 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure ChangeResolution */

+

+/* 152 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 154 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 158 */	NdrFcShort( 0x5 ),	/* 5 */

+/* 160 */	NdrFcShort( 0x30 ),	/* ARM64 Stack size/offset = 48 */

+/* 162 */	NdrFcShort( 0x20 ),	/* 32 */

+/* 164 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 166 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+			0x5,		/* 5 */

+/* 168 */	0x10,		/* 16 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 170 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 172 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 174 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 176 */	NdrFcShort( 0x5 ),	/* 5 */

+/* 178 */	0x5,		/* 5 */

+			0x80,		/* 128 */

+/* 180 */	0x81,		/* 129 */

+			0x82,		/* 130 */

+/* 182 */	0x83,		/* 131 */

+			0x84,		/* 132 */

+

+	/* Parameter width */

+

+/* 184 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 186 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 188 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter height */

+

+/* 190 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 192 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 194 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter dpi_x */

+

+/* 196 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 198 */	NdrFcShort( 0x18 ),	/* ARM64 Stack size/offset = 24 */

+/* 200 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Parameter dpi_y */

+

+/* 202 */	NdrFcShort( 0x48 ),	/* Flags:  in, base type, */

+/* 204 */	NdrFcShort( 0x20 ),	/* ARM64 Stack size/offset = 32 */

+/* 206 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Return value */

+

+/* 208 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 210 */	NdrFcShort( 0x28 ),	/* ARM64 Stack size/offset = 40 */

+/* 212 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+	/* Procedure InjectSas */

+

+/* 214 */	0x33,		/* FC_AUTO_HANDLE */

+			0x6c,		/* Old Flags:  object, Oi2 */

+/* 216 */	NdrFcLong( 0x0 ),	/* 0 */

+/* 220 */	NdrFcShort( 0x6 ),	/* 6 */

+/* 222 */	NdrFcShort( 0x10 ),	/* ARM64 Stack size/offset = 16 */

+/* 224 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 226 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 228 */	0x44,		/* Oi2 Flags:  has return, has ext, */

+			0x1,		/* 1 */

+/* 230 */	0xc,		/* 12 */

+			0x1,		/* Ext Flags:  new corr desc, */

+/* 232 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 234 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 236 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 238 */	NdrFcShort( 0x1 ),	/* 1 */

+/* 240 */	0x1,		/* 1 */

+			0x80,		/* 128 */

+

+	/* Return value */

+

+/* 242 */	NdrFcShort( 0x70 ),	/* Flags:  out, return, base type, */

+/* 244 */	NdrFcShort( 0x8 ),	/* ARM64 Stack size/offset = 8 */

+/* 246 */	0x8,		/* FC_LONG */

+			0x0,		/* 0 */

+

+			0x0

+        }

+    };

+

+static const chromoting_lib_MIDL_TYPE_FORMAT_STRING chromoting_lib__MIDL_TypeFormatString =

+    {

+        0,

+        {

+			NdrFcShort( 0x0 ),	/* 0 */

+/*  2 */	

+			0x12, 0x0,	/* FC_UP */

+/*  4 */	NdrFcShort( 0xe ),	/* Offset= 14 (18) */

+/*  6 */	

+			0x1b,		/* FC_CARRAY */

+			0x1,		/* 1 */

+/*  8 */	NdrFcShort( 0x2 ),	/* 2 */

+/* 10 */	0x9,		/* Corr desc: FC_ULONG */

+			0x0,		/*  */

+/* 12 */	NdrFcShort( 0xfffc ),	/* -4 */

+/* 14 */	NdrFcShort( 0x1 ),	/* Corr flags:  early, */

+/* 16 */	0x6,		/* FC_SHORT */

+			0x5b,		/* FC_END */

+/* 18 */	

+			0x17,		/* FC_CSTRUCT */

+			0x3,		/* 3 */

+/* 20 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 22 */	NdrFcShort( 0xfff0 ),	/* Offset= -16 (6) */

+/* 24 */	0x8,		/* FC_LONG */

+			0x8,		/* FC_LONG */

+/* 26 */	0x5c,		/* FC_PAD */

+			0x5b,		/* FC_END */

+/* 28 */	0xb4,		/* FC_USER_MARSHAL */

+			0x83,		/* 131 */

+/* 30 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 32 */	NdrFcShort( 0x8 ),	/* 8 */

+/* 34 */	NdrFcShort( 0x0 ),	/* 0 */

+/* 36 */	NdrFcShort( 0xffde ),	/* Offset= -34 (2) */

+/* 38 */	

+			0x2f,		/* FC_IP */

+			0x5a,		/* FC_CONSTANT_IID */

+/* 40 */	NdrFcLong( 0xb59b96da ),	/* -1248094502 */

+/* 44 */	NdrFcShort( 0x83cb ),	/* -31797 */

+/* 46 */	NdrFcShort( 0x40ee ),	/* 16622 */

+/* 48 */	0x9b,		/* 155 */

+			0x91,		/* 145 */

+/* 50 */	0xc3,		/* 195 */

+			0x77,		/* 119 */

+/* 52 */	0x40,		/* 64 */

+			0xf,		/* 15 */

+/* 54 */	0xc3,		/* 195 */

+			0xe3,		/* 227 */

+

+			0x0

+        }

+    };

+

+static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[ WIRE_MARSHAL_TABLE_SIZE ] = 

+        {

+            

+            {

+            BSTR_UserSize

+            ,BSTR_UserMarshal

+            ,BSTR_UserUnmarshal

+            ,BSTR_UserFree

+            }

+

+        };

+

+

+

+/* Object interface: IUnknown, ver. 0.0,

+   GUID={0x00000000,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */

+

+

+/* Object interface: IRdpDesktopSessionEventHandler, ver. 0.0,

+   GUID={0xb59b96da,0x83cb,0x40ee,{0x9b,0x91,0xc3,0x77,0x40,0x0f,0xc3,0xe3}} */

+

+#pragma code_seg(".orpc")

+static const unsigned short IRdpDesktopSessionEventHandler_FormatStringOffsetTable[] =

+    {

+    0,

+    34

+    };

+

+static const MIDL_STUBLESS_PROXY_INFO IRdpDesktopSessionEventHandler_ProxyInfo =

+    {

+    &Object_StubDesc,

+    chromoting_lib__MIDL_ProcFormatString.Format,

+    &IRdpDesktopSessionEventHandler_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0

+    };

+

+

+static const MIDL_SERVER_INFO IRdpDesktopSessionEventHandler_ServerInfo = 

+    {

+    &Object_StubDesc,

+    0,

+    chromoting_lib__MIDL_ProcFormatString.Format,

+    &IRdpDesktopSessionEventHandler_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0,

+    0};

+CINTERFACE_PROXY_VTABLE(5) _IRdpDesktopSessionEventHandlerProxyVtbl = 

+{

+    &IRdpDesktopSessionEventHandler_ProxyInfo,

+    &IID_IRdpDesktopSessionEventHandler,

+    IUnknown_QueryInterface_Proxy,

+    IUnknown_AddRef_Proxy,

+    IUnknown_Release_Proxy ,

+    (void *) (INT_PTR) -1 /* IRdpDesktopSessionEventHandler::OnRdpConnected */ ,

+    (void *) (INT_PTR) -1 /* IRdpDesktopSessionEventHandler::OnRdpClosed */

+};

+

+const CInterfaceStubVtbl _IRdpDesktopSessionEventHandlerStubVtbl =

+{

+    &IID_IRdpDesktopSessionEventHandler,

+    &IRdpDesktopSessionEventHandler_ServerInfo,

+    5,

+    0, /* pure interpreted */

+    CStdStubBuffer_METHODS

+};

+

+

+/* Object interface: IRdpDesktopSession, ver. 0.0,

+   GUID={0x6a7699f0,0xee43,0x43e7,{0xaa,0x30,0xa6,0x73,0x8f,0x9b,0xd4,0x70}} */

+

+#pragma code_seg(".orpc")

+static const unsigned short IRdpDesktopSession_FormatStringOffsetTable[] =

+    {

+    68,

+    34,

+    152,

+    214

+    };

+

+static const MIDL_STUBLESS_PROXY_INFO IRdpDesktopSession_ProxyInfo =

+    {

+    &Object_StubDesc,

+    chromoting_lib__MIDL_ProcFormatString.Format,

+    &IRdpDesktopSession_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0

+    };

+

+

+static const MIDL_SERVER_INFO IRdpDesktopSession_ServerInfo = 

+    {

+    &Object_StubDesc,

+    0,

+    chromoting_lib__MIDL_ProcFormatString.Format,

+    &IRdpDesktopSession_FormatStringOffsetTable[-3],

+    0,

+    0,

+    0,

+    0};

+CINTERFACE_PROXY_VTABLE(7) _IRdpDesktopSessionProxyVtbl = 

+{

+    &IRdpDesktopSession_ProxyInfo,

+    &IID_IRdpDesktopSession,

+    IUnknown_QueryInterface_Proxy,

+    IUnknown_AddRef_Proxy,

+    IUnknown_Release_Proxy ,

+    (void *) (INT_PTR) -1 /* IRdpDesktopSession::Connect */ ,

+    (void *) (INT_PTR) -1 /* IRdpDesktopSession::Disconnect */ ,

+    (void *) (INT_PTR) -1 /* IRdpDesktopSession::ChangeResolution */ ,

+    (void *) (INT_PTR) -1 /* IRdpDesktopSession::InjectSas */

+};

+

+const CInterfaceStubVtbl _IRdpDesktopSessionStubVtbl =

+{

+    &IID_IRdpDesktopSession,

+    &IRdpDesktopSession_ServerInfo,

+    7,

+    0, /* pure interpreted */

+    CStdStubBuffer_METHODS

+};

+

+static const MIDL_STUB_DESC Object_StubDesc = 

+    {

+    0,

+    NdrOleAllocate,

+    NdrOleFree,

+    0,

+    0,

+    0,

+    0,

+    0,

+    chromoting_lib__MIDL_TypeFormatString.Format,

+    1, /* -error bounds_check flag */

+    0x50002, /* Ndr library version */

+    0,

+    0x801026e, /* MIDL Version 8.1.622 */

+    0,

+    UserMarshalRoutines,

+    0,  /* notify & notify_flag routine table */

+    0x1, /* MIDL flag */

+    0, /* cs routines */

+    0,   /* proxy/server info */

+    0

+    };

+

+const CInterfaceProxyVtbl * const _chromoting_lib_ProxyVtblList[] = 

+{

+    ( CInterfaceProxyVtbl *) &_IRdpDesktopSessionEventHandlerProxyVtbl,

+    ( CInterfaceProxyVtbl *) &_IRdpDesktopSessionProxyVtbl,

+    0

+};

+

+const CInterfaceStubVtbl * const _chromoting_lib_StubVtblList[] = 

+{

+    ( CInterfaceStubVtbl *) &_IRdpDesktopSessionEventHandlerStubVtbl,

+    ( CInterfaceStubVtbl *) &_IRdpDesktopSessionStubVtbl,

+    0

+};

+

+PCInterfaceName const _chromoting_lib_InterfaceNamesList[] = 

+{

+    "IRdpDesktopSessionEventHandler",

+    "IRdpDesktopSession",

+    0

+};

+

+

+#define _chromoting_lib_CHECK_IID(n)	IID_GENERIC_CHECK_IID( _chromoting_lib, pIID, n)

+

+int __stdcall _chromoting_lib_IID_Lookup( const IID * pIID, int * pIndex )

+{

+    IID_BS_LOOKUP_SETUP

+

+    IID_BS_LOOKUP_INITIAL_TEST( _chromoting_lib, 2, 1 )

+    IID_BS_LOOKUP_RETURN_RESULT( _chromoting_lib, 2, *pIndex )

+    

+}

+

+const ExtendedProxyFileInfo chromoting_lib_ProxyFileInfo = 

+{

+    (PCInterfaceProxyVtblList *) & _chromoting_lib_ProxyVtblList,

+    (PCInterfaceStubVtblList *) & _chromoting_lib_StubVtblList,

+    (const PCInterfaceName * ) & _chromoting_lib_InterfaceNamesList,

+    0, /* no delegation */

+    & _chromoting_lib_IID_Lookup, 

+    2,

+    2,

+    0, /* table of [async_uuid] interfaces */

+    0, /* Filler1 */

+    0, /* Filler2 */

+    0  /* Filler3 */

+};

+#if _MSC_VER >= 1200

+#pragma warning(pop)

+#endif

+

+

+#endif /* defined(_M_ARM64)*/

+

diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 8442b28..2fec970 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -30691,6 +30691,7 @@
   <int value="-1871185948" label="VrLaunchIntents:disabled"/>
   <int value="-1870961970" label="enable-filemanager-mtp"/>
   <int value="-1869845022" label="force-show-update-menu-item"/>
+  <int value="-1869432243" label="GoogleBrandedContextMenu:disabled"/>
   <int value="-1868978829" label="spurious-power-button-accel-count"/>
   <int value="-1868284723" label="DirectManipulationStylus:disabled"/>
   <int value="-1867382602" label="WebRTC-H264WithOpenH264FFmpeg:enabled"/>
@@ -31417,6 +31418,7 @@
   <int value="-641719457" label="disable-compositor-touch-hit-testing"/>
   <int value="-639026783" label="disable-gpu-appcontainer"/>
   <int value="-638952203" label="RendererSideResourceScheduler:disabled"/>
+  <int value="-634122679" label="GoogleBrandedContextMenu:enabled"/>
   <int value="-633274640" label="WebRTCPipeWireCapturer:enabled"/>
   <int value="-632030508" label="NativeWindowNavButtons:disabled"/>
   <int value="-631740127" label="inert-visual-viewport"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index c6a0d4e9..403ede30 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -12838,7 +12838,8 @@
 
 <histogram name="BrowserDialogs.ExternalProtocol.HandleState"
     enum="HandleStateType">
-  <owner>ramyasharma@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <owner>meacer@chromium.org</owner>
   <summary>
     Whether or not the user checked the option in the external protocol dialog
     to remember their choice of opening or not opening the specified app.
@@ -55627,7 +55628,6 @@
     Deprecated 03/2017 in Issue 703460.
   </obsolete>
   <owner>palmer@chromium.org</owner>
-  <owner>cbentzel@chromium.org</owner>
   <summary>
     Whether the navigation was to a URL that had embedded credentials.
   </summary>
@@ -55699,7 +55699,6 @@
     Deprecated 03/2017 in Issue 703460.
   </obsolete>
   <owner>palmer@chromium.org</owner>
-  <owner>cbentzel@chromium.org</owner>
   <summary>
     Whether the main-frame navigation was to a URL that had embedded
     credentials.
@@ -60061,7 +60060,7 @@
 
 <histogram name="Net.HttpAuthCount" enum="HttpAuthCount">
   <owner>asanka@chromium.org</owner>
-  <owner>cbentzel@chromium.org</owner>
+  <owner>mmenke@chromium.org</owner>
   <summary>
     Per-authentication-scheme counts of authentication attempts and rejections.
   </summary>
@@ -60085,7 +60084,7 @@
 
 <histogram name="Net.HttpAuthTarget" enum="HttpAuthTarget">
   <owner>asanka@chromium.org</owner>
-  <owner>cbentzel@chromium.org</owner>
+  <owner>mmenke@chromium.org</owner>
   <summary>
     Per-authentication-scheme counts of authentication targets, such as secure
     servers or proxies.
@@ -61676,7 +61675,7 @@
 </histogram>
 
 <histogram name="Net.ProxyScriptFetcher.FirstByteDuration" units="ms">
-  <owner>cbentzel@chromium.org</owner>
+  <owner>eroman@chromium.org</owner>
   <summary>
     The time taken from requesting a PAC script to receiving the first byte of
     the response body on successful fetches. This does not include time spent
@@ -61687,7 +61686,7 @@
 </histogram>
 
 <histogram name="Net.ProxyScriptFetcher.SuccessDuration" units="ms">
-  <owner>cbentzel@chromium.org</owner>
+  <owner>eroman@chromium.org</owner>
   <summary>
     The time taken to successfully fetch a PAC script. This does not include
     time spent doing proxy auto-discovery, or failed attempts at retrieving PAC
diff --git a/tools/vscode/settings.json5 b/tools/vscode/settings.json5
index bfdcbac..26410388 100644
--- a/tools/vscode/settings.json5
+++ b/tools/vscode/settings.json5
@@ -11,10 +11,13 @@
   "editor.detectIndentation": false,
   // Add a line at 80 characters.
   "editor.rulers": [80],
-  // Trim tailing whitespace on save.
-  "files.trimTrailingWhitespace": true,
   // Forces LF instead of "auto" which uses CRLF on Windows.
   "files.eol": "\n",
+  // Trim tailing whitespace on save.
+  "files.trimTrailingWhitespace": true,
+  // Insert trimmed final new line.
+  "files.insertFinalNewline": true,
+  "files.trimFinalNewlines": true,
 
   "files.associations": {
     // Adds xml syntax highlighting for grd files.
@@ -45,13 +48,13 @@
   "annotator.annotationColumnWidth": "24em",
 
   // C++ clang format settings.
-  "C_Cpp.clang_format_path": "${workspaceRoot}/third_party/depot_tools/clang-format",
+  "C_Cpp.clang_format_path": "${workspaceFolder}/third_party/depot_tools/clang-format",
   "C_Cpp.clang_format_sortIncludes": true,
   "C_Cpp.clang_format_formatOnSave": true,
 
   // YouCompleteMe
   "ycmd.path": "<full_path_to_your_home>/.ycmd", // Please replace this path
-  "ycmd.global_extra_config": "${workspaceRoot}/tools/vim/chromium.ycm_extra_conf.py",
+  "ycmd.global_extra_config": "${workspaceFolder}/tools/vim/chromium.ycm_extra_conf.py",
   "ycmd.confirm_extra_conf": false,
 
   // Optional: Highlight current line at the left of the editor.
diff --git a/ui/aura/mus/OWNERS b/ui/aura/mus/OWNERS
new file mode 100644
index 0000000..280badf
--- /dev/null
+++ b/ui/aura/mus/OWNERS
@@ -0,0 +1 @@
+file://services/ws/OWNERS
diff --git a/ui/aura/mus/client_side_window_move_handler.cc b/ui/aura/mus/client_side_window_move_handler.cc
index bc187faa..e270f01 100644
--- a/ui/aura/mus/client_side_window_move_handler.cc
+++ b/ui/aura/mus/client_side_window_move_handler.cc
@@ -58,6 +58,15 @@
   last_target_.Add(window);
   last_location_ = event->location();
   last_component_ = component;
+  UpdateWindowResizeShadow(
+      window, ui::IsResizingComponent(component) ? component : HTNOWHERE);
+}
+
+void ClientSideWindowMoveHandler::UpdateWindowResizeShadow(Window* window,
+                                                           int component) {
+  client_->SetWindowResizeShadow(window->GetRootWindow(), component);
+  last_shadow_target_.RemoveAll();
+  last_shadow_target_.Add(window);
 }
 
 void ClientSideWindowMoveHandler::MaybePerformWindowMove(
@@ -94,10 +103,14 @@
   }
   switch (event->type()) {
     case ui::ET_MOUSE_EXITED:
-      if (last_component_ != HTNOWHERE &&
-          !last_shadow_target_.windows().empty()) {
-        client_->SetWindowResizeShadow(last_shadow_target_.Pop(), HTNOWHERE);
+      if (!last_shadow_target_.Contains(
+              static_cast<Window*>(event->target())) ||
+          last_component_ == HTNOWHERE) {
+        return;
       }
+
+      client_->SetWindowResizeShadow(last_shadow_target_.Pop()->GetRootWindow(),
+                                     HTNOWHERE);
       last_component_ = HTNOWHERE;
       break;
 
@@ -112,9 +125,7 @@
       if (component == last_component_)
         return;
       last_component_ = component;
-      client_->SetWindowResizeShadow(window->GetRootWindow(), last_component_);
-      last_shadow_target_.RemoveAll();
-      last_shadow_target_.Add(window->GetRootWindow());
+      UpdateWindowResizeShadow(window, last_component_);
       break;
     }
 
diff --git a/ui/aura/mus/client_side_window_move_handler.h b/ui/aura/mus/client_side_window_move_handler.h
index 0ebf81c..107458fa 100644
--- a/ui/aura/mus/client_side_window_move_handler.h
+++ b/ui/aura/mus/client_side_window_move_handler.h
@@ -17,6 +17,7 @@
 namespace aura {
 
 class Env;
+class Window;
 class WindowTreeClient;
 
 // ClientSideWindowMoveHandler handles mouse/gesture events and performs the
@@ -31,6 +32,9 @@
   // the event will not involve window move.
   void MaybeSetupLastTarget(ui::LocatedEvent* event);
 
+  // Updates the resize shadow for |window| to |component| in the window server.
+  void UpdateWindowResizeShadow(Window* window, int component);
+
   // Conduct the window move.
   void MaybePerformWindowMove(ui::LocatedEvent* event,
                               ws::mojom::MoveLoopSource source);
diff --git a/ui/aura/mus/client_side_window_move_handler_unittest.cc b/ui/aura/mus/client_side_window_move_handler_unittest.cc
index 9e3a72fb..1a4fe5d 100644
--- a/ui/aura/mus/client_side_window_move_handler_unittest.cc
+++ b/ui/aura/mus/client_side_window_move_handler_unittest.cc
@@ -5,6 +5,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/mus/in_flight_change.h"
 #include "ui/aura/mus/window_tree_client_test_observer.h"
+#include "ui/aura/mus/window_tree_host_mus.h"
+#include "ui/aura/mus/window_tree_host_mus_init_params.h"
 #include "ui/aura/test/aura_mus_test_base.h"
 #include "ui/aura/test/mus/test_window_tree.h"
 #include "ui/aura/test/test_window_delegate.h"
@@ -192,6 +194,7 @@
   MoveInputBy(10, 10);
   EXPECT_TRUE(observer.in_window_move());
   EXPECT_EQ(HTCAPTION, window_tree()->last_move_hit_test());
+  EXPECT_EQ(HTNOWHERE, window_tree()->last_window_resize_shadow());
   window_tree()->AckAllChanges();
   EXPECT_FALSE(observer.in_window_move());
 }
@@ -205,6 +208,7 @@
   MoveInputBy(-10, -10);
   EXPECT_TRUE(observer.in_window_move());
   EXPECT_EQ(HTBOTTOMRIGHT, window_tree()->last_move_hit_test());
+  EXPECT_EQ(HTBOTTOMRIGHT, window_tree()->last_window_resize_shadow());
   window_tree()->AckAllChanges();
   EXPECT_FALSE(observer.in_window_move());
 }
@@ -220,6 +224,37 @@
   window_tree()->AckAllChanges();
 }
 
+TEST_P(ClientSideWindowMoveHandlerTest, MouseExitDoesNotCancelResize) {
+  // Create another window-tree-host and sets the capture there.
+  auto host2 = std::make_unique<WindowTreeHostMus>(
+      CreateInitParamsForTopLevel(window_tree_client_impl()));
+  host2->InitHost();
+  gfx::Rect host2_bounds = host()->GetBoundsInPixels();
+  host2_bounds.Offset(30, 30);
+  host2->SetBoundsInPixels(host2_bounds);
+  host2->window()->Show();
+
+  test::TestWindowDelegate test_delegate;
+  std::unique_ptr<Window> window2(
+      CreateNormalWindow(12, host2->window(), &test_delegate));
+  window2->SetCapture();
+  window_tree()->AckAllChanges();
+
+  WindowMoveObserver observer(window_tree_client_impl());
+
+  // Makes the mouse event to cause window resize; since |window2| has the
+  // capture, this should cause MOUSE_EXITED on |window2|, but that shouldn't
+  // affect the behavior of resizing on the target window.
+  MoveInputTo(GetWindowBounds().origin() + gfx::Vector2d(1, 1));
+  PressInput();
+  MoveInputBy(-10, -10);
+  EXPECT_TRUE(observer.in_window_move());
+  EXPECT_EQ(HTTOPLEFT, window_tree()->last_move_hit_test());
+  EXPECT_EQ(HTTOPLEFT, window_tree()->last_window_resize_shadow());
+  window_tree()->AckAllChanges();
+  EXPECT_FALSE(observer.in_window_move());
+}
+
 INSTANTIATE_TEST_CASE_P(,
                         ClientSideWindowMoveHandlerTest,
                         ::testing::Values("mouse", "touch"));
diff --git a/ui/aura/mus/drag_drop_controller_mus.cc b/ui/aura/mus/drag_drop_controller_mus.cc
index 43452de..5f8746a2 100644
--- a/ui/aura/mus/drag_drop_controller_mus.cc
+++ b/ui/aura/mus/drag_drop_controller_mus.cc
@@ -15,12 +15,14 @@
 #include "services/ws/public/mojom/window_tree_constants.mojom.h"
 #include "ui/aura/client/drag_drop_client_observer.h"
 #include "ui/aura/client/drag_drop_delegate.h"
+#include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/mus/drag_drop_controller_host.h"
 #include "ui/aura/mus/mus_types.h"
 #include "ui/aura/mus/os_exchange_data_provider_mus.h"
 #include "ui/aura/mus/window_mus.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/dragdrop/drop_target_event.h"
 
@@ -53,6 +55,14 @@
   // StartDragDrop() runs a nested run loop. This closure is used to quit
   // the run loop when the drag completes.
   base::Closure runloop_quit_closure;
+
+  // The starting location of the drag gesture in screen coordinates.
+  gfx::Point start_screen_location;
+
+  // A tracker for the window that received the initial drag and drop events,
+  // used to send ET_GESTURE_LONG_TAP when the user presses, pauses, and
+  // releases a touch without any movement; it is reset if movement is detected.
+  WindowTracker source_window_tracker;
 };
 
 DragDropControllerMus::DragDropControllerMus(
@@ -122,6 +132,23 @@
   DCHECK(current_drag_state_);
   for (client::DragDropClientObserver& observer : observers_)
     observer.OnDragEnded();
+
+  // When the user presses, pauses, and releases a touch without any movement,
+  // that gesture should be interpreted as a long tap and show a menu, etc.
+  // See Classic Ash's long tap event handling in ash::DragDropController.
+  if (action_taken == ws::mojom::kDropEffectNone &&
+      !current_drag_state_->source_window_tracker.windows().empty()) {
+    auto* window = current_drag_state_->source_window_tracker.windows()[0];
+    gfx::Point location = current_drag_state_->start_screen_location;
+    if (auto* client = client::GetScreenPositionClient(window->GetRootWindow()))
+      client->ConvertPointFromScreen(window, &location);
+    ui::GestureEventDetails details(ui::ET_GESTURE_LONG_TAP);
+    details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+    ui::GestureEvent long_tap(location.x(), location.y(), ui::EF_NONE,
+                              base::TimeTicks::Now(), details);
+    window->delegate()->OnEvent(&long_tap);
+  }
+
   current_drag_state_->completed_action = action_taken;
   current_drag_state_->runloop_quit_closure.Run();
   current_drag_state_ = nullptr;
@@ -144,9 +171,10 @@
   WindowMus* source_window_mus = WindowMus::Get(source_window);
   const uint32_t change_id =
       drag_drop_controller_host_->CreateChangeIdForDrag(source_window_mus);
-  CurrentDragState current_drag_state = {source_window_mus->server_id(),
-                                         change_id, ws::mojom::kDropEffectNone,
-                                         data, run_loop.QuitClosure()};
+  CurrentDragState current_drag_state = {
+      source_window_mus->server_id(), change_id,
+      ws::mojom::kDropEffectNone,     data,
+      run_loop.QuitClosure(),         screen_location};
 
   // current_drag_state_ will be reset in |OnPerformDragDropCompleted| before
   // run_loop.Run() quits.
@@ -156,6 +184,8 @@
   if (source != ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE) {
     // TODO(erg): This collapses both touch and pen events to touch.
     mojo_source = ui::mojom::PointerKind::TOUCH;
+    // Track the source window, to possibly send ET_GESTURE_LONG_TAP later.
+    current_drag_state.source_window_tracker.Add(source_window);
   }
 
   std::map<std::string, std::vector<uint8_t>> drag_data =
@@ -201,6 +231,9 @@
     const gfx::PointF& location,
     uint32_t effect_bitmask,
     bool is_enter) {
+  // Reset the tracker on drag movement, ET_GESTURE_LONG_TAP will not be needed.
+  current_drag_state_->source_window_tracker.RemoveAll();
+
   client::DragDropDelegate* drag_drop_delegate =
       window ? client::GetDragDropDelegate(window->GetWindow()) : nullptr;
   WindowTreeHost* window_tree_host =
diff --git a/ui/events/devices/input_device_observer_win.cc b/ui/events/devices/input_device_observer_win.cc
index c8bd203..dc5df14 100644
--- a/ui/events/devices/input_device_observer_win.cc
+++ b/ui/events/devices/input_device_observer_win.cc
@@ -24,31 +24,20 @@
 
 namespace ui {
 
-namespace {
-
 // The registry subkey that contains information about the state of the
 // detachable/convertible laptop, it tells if the device has an accessible
-// keyboard.
-// OEMs are expected to follow these guidelines to report docked/undocked state
+// keyboard. OEMs are expected to follow these guidelines to report
+// docked/undocked state
 // https://msdn.microsoft.com/en-us/windows/hardware/commercialize/customize/desktop/unattend/microsoft-windows-gpiobuttons-convertibleslatemode
-const base::char16 kRegistryPriorityControl[] =
-    L"System\\CurrentControlSet\\Control\\PriorityControl";
-
-const base::char16 kRegistryConvertibleSlateModeKey[] = L"ConvertibleSlateMode";
-
-}  // namespace
-
-InputDeviceObserverWin::InputDeviceObserverWin() : weak_factory_(this) {
-  registry_key_.reset(new base::win::RegKey(
-      HKEY_LOCAL_MACHINE, kRegistryPriorityControl, KEY_NOTIFY | KEY_READ));
-
-  if (registry_key_->Valid()) {
-    slate_mode_enabled_ = IsSlateModeEnabled(registry_key_.get());
+InputDeviceObserverWin::InputDeviceObserverWin()
+    : registry_key_(HKEY_LOCAL_MACHINE,
+                    L"System\\CurrentControlSet\\Control\\PriorityControl",
+                    KEY_NOTIFY | KEY_READ) {
+  if (registry_key_.Valid()) {
+    slate_mode_enabled_ = IsSlateModeEnabled();
     // Start watching the registry for changes.
-    base::win::RegKey::ChangeCallback callback =
-        base::BindOnce(&InputDeviceObserverWin::OnRegistryKeyChanged,
-                       weak_factory_.GetWeakPtr(), registry_key_.get());
-    registry_key_->StartWatching(std::move(callback));
+    registry_key_.StartWatching(base::BindOnce(
+        &InputDeviceObserverWin::OnRegistryKeyChanged, base::Unretained(this)));
   }
 }
 
@@ -60,17 +49,13 @@
 
 InputDeviceObserverWin::~InputDeviceObserverWin() {}
 
-void InputDeviceObserverWin::OnRegistryKeyChanged(base::win::RegKey* key) {
-  if (!key)
-    return;
-
+void InputDeviceObserverWin::OnRegistryKeyChanged() {
   // |OnRegistryKeyChanged| is removed as an observer when the ChangeCallback is
   // called, so we need to re-register.
-  key->StartWatching(base::Bind(&InputDeviceObserverWin::OnRegistryKeyChanged,
-                                weak_factory_.GetWeakPtr(),
-                                base::Unretained(key)));
+  registry_key_.StartWatching(base::BindOnce(
+      &InputDeviceObserverWin::OnRegistryKeyChanged, base::Unretained(this)));
 
-  bool new_slate_mode = IsSlateModeEnabled(key);
+  bool new_slate_mode = IsSlateModeEnabled();
   if (slate_mode_enabled_ == new_slate_mode)
     return;
 
@@ -79,12 +64,12 @@
   slate_mode_enabled_ = new_slate_mode;
 }
 
-bool InputDeviceObserverWin::IsSlateModeEnabled(base::win::RegKey* key) {
-  DWORD slate_enabled;
-  if (key->ReadValueDW(kRegistryConvertibleSlateModeKey, &slate_enabled) !=
-      ERROR_SUCCESS)
-    return false;
-  return slate_enabled == 1;
+bool InputDeviceObserverWin::IsSlateModeEnabled() {
+  DCHECK(registry_key_.Valid());
+  DWORD slate_enabled = 0;
+  return registry_key_.ReadValueDW(L"ConvertibleSlateMode", &slate_enabled) ==
+             ERROR_SUCCESS &&
+         slate_enabled == 1;
 }
 
 void InputDeviceObserverWin::AddObserver(InputDeviceEventObserver* observer) {
diff --git a/ui/events/devices/input_device_observer_win.h b/ui/events/devices/input_device_observer_win.h
index 1077779..049cf4e 100644
--- a/ui/events/devices/input_device_observer_win.h
+++ b/ui/events/devices/input_device_observer_win.h
@@ -15,6 +15,7 @@
 }
 
 namespace ui {
+
 class EVENTS_DEVICES_EXPORT InputDeviceObserverWin {
  public:
   static InputDeviceObserverWin* GetInstance();
@@ -27,22 +28,20 @@
   InputDeviceObserverWin();
 
  private:
-  void OnRegistryKeyChanged(base::win::RegKey* key);
-  bool IsSlateModeEnabled(base::win::RegKey* key);
+  friend struct base::DefaultSingletonTraits<InputDeviceObserverWin>;
+
+  void OnRegistryKeyChanged();
+  bool IsSlateModeEnabled();
   void NotifyObserversKeyboardDeviceConfigurationChanged();
   void NotifyObserversTouchpadDeviceConfigurationChanged();
 
-  std::unique_ptr<base::win::RegKey> registry_key_;
+  bool slate_mode_enabled_ = false;
+  base::win::RegKey registry_key_;
   base::ObserverList<InputDeviceEventObserver>::Unchecked observers_;
-  bool slate_mode_enabled_;
-
-  friend struct base::DefaultSingletonTraits<InputDeviceObserverWin>;
-
-  base::WeakPtrFactory<InputDeviceObserverWin> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(InputDeviceObserverWin);
 };
 
 }  // namespace ui
 
-#endif  // UI_EVENTS_DEVICES_INPUT_DEVICE_OBSERVER_WIN_H_
\ No newline at end of file
+#endif  // UI_EVENTS_DEVICES_INPUT_DEVICE_OBSERVER_WIN_H_
diff --git a/ui/gfx/rrect_f.cc b/ui/gfx/rrect_f.cc
index 4a8bf06..8e7e825 100644
--- a/ui/gfx/rrect_f.cc
+++ b/ui/gfx/rrect_f.cc
@@ -12,6 +12,25 @@
 
 namespace gfx {
 
+// Directly sets all four corners.
+RRectF::RRectF(float x,
+               float y,
+               float width,
+               float height,
+               float upper_left_x,
+               float upper_left_y,
+               float upper_right_x,
+               float upper_right_y,
+               float lower_right_x,
+               float lower_right_y,
+               float lower_left_x,
+               float lower_left_y)
+    : RRectF(x, y, width, height, upper_left_x, upper_left_y) {
+  SetCornerRadii(RRectF::Corner::kUpperRight, upper_right_x, upper_right_y);
+  SetCornerRadii(RRectF::Corner::kLowerRight, lower_right_x, lower_right_y);
+  SetCornerRadii(RRectF::Corner::kLowerLeft, lower_left_x, lower_left_y);
+}
+
 gfx::Vector2dF RRectF::GetSimpleRadii() const {
   DCHECK(GetType() <= Type::kOval);
   SkPoint result = skrrect_.getSimpleRadii();
@@ -118,4 +137,27 @@
   return ss.str();
 }
 
+namespace {
+inline bool AboveTol(float val1, float val2, float tolerance) {
+  return (std::abs(val1 - val2) > tolerance);
+}
+}  // namespace
+
+bool RRectF::ApproximatelyEqual(const RRectF& rect, float tolerance) const {
+  if (AboveTol(skrrect_.rect().x(), rect.skrrect_.rect().x(), tolerance) ||
+      AboveTol(skrrect_.rect().y(), rect.skrrect_.rect().y(), tolerance) ||
+      AboveTol(skrrect_.width(), rect.skrrect_.width(), tolerance) ||
+      AboveTol(skrrect_.height(), rect.skrrect_.height(), tolerance))
+    return false;
+  for (int i = 0; i < 4; i++) {
+    SkVector r1 = skrrect_.radii(SkRRect::Corner(i));
+    SkVector r2 = rect.skrrect_.radii(SkRRect::Corner(i));
+    if (std::abs(r1.x() - r2.x()) > tolerance ||
+        std::abs(r1.y() - r2.y()) > tolerance) {
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace gfx
diff --git a/ui/gfx/rrect_f.h b/ui/gfx/rrect_f.h
index 536f8bd..0acb013 100644
--- a/ui/gfx/rrect_f.h
+++ b/ui/gfx/rrect_f.h
@@ -34,6 +34,40 @@
       : skrrect_(SkRRect::MakeRectXY(SkRect::MakeXYWH(x, y, width, height),
                                      x_rad,
                                      y_rad)) {}
+  // Directly sets all four corners.
+  RRectF(float x,
+         float y,
+         float width,
+         float height,
+         float upper_left_x,
+         float upper_left_y,
+         float upper_right_x,
+         float upper_right_y,
+         float lower_right_x,
+         float lower_right_y,
+         float lower_left_x,
+         float lower_left_y);
+  RRectF(const gfx::RectF& rect,
+         float upper_left_x,
+         float upper_left_y,
+         float upper_right_x,
+         float upper_right_y,
+         float lower_right_x,
+         float lower_right_y,
+         float lower_left_x,
+         float lower_left_y)
+      : RRectF(rect.x(),
+               rect.y(),
+               rect.width(),
+               rect.height(),
+               upper_left_x,
+               upper_left_y,
+               upper_right_x,
+               upper_right_y,
+               lower_right_x,
+               lower_right_y,
+               lower_left_x,
+               lower_left_y) {}
 
   // The rectangular portion of the RRectF, without the corner radii.
   gfx::RectF rect() const { return gfx::SkRectToRectF(skrrect_.rect()); }
@@ -102,6 +136,7 @@
   const RRectF& operator-=(const gfx::Vector2dF& offset);
 
   std::string ToString() const;
+  bool ApproximatelyEqual(const RRectF& rect, float tolerance) const;
 
   // Insets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may
   // be positive, negative, or zero. If either corner radius is zero, the corner
diff --git a/ui/gfx/rrect_f_unittest.cc b/ui/gfx/rrect_f_unittest.cc
index 5c31570..20d62a1 100644
--- a/ui/gfx/rrect_f_unittest.cc
+++ b/ui/gfx/rrect_f_unittest.cc
@@ -102,17 +102,20 @@
   RRectF a(40, 50, 60, 70, 0);
   CheckRadii(a, 0, 0, 0, 0, 0, 0, 0, 0);
 
-  a.SetCornerRadii(RRectF::Corner::kUpperLeft, gfx::Vector2dF(1, 2));
+  a.SetCornerRadii(RRectF::Corner::kUpperLeft, 1, 2);
   CheckRadii(a, 1, 2, 0, 0, 0, 0, 0, 0);
 
-  a.SetCornerRadii(RRectF::Corner::kUpperRight, gfx::Vector2dF(3, 4));
+  a.SetCornerRadii(RRectF::Corner::kUpperRight, 3, 4);
   CheckRadii(a, 1, 2, 3, 4, 0, 0, 0, 0);
 
-  a.SetCornerRadii(RRectF::Corner::kLowerRight, gfx::Vector2dF(5, 6));
+  a.SetCornerRadii(RRectF::Corner::kLowerRight, 5, 6);
   CheckRadii(a, 1, 2, 3, 4, 5, 6, 0, 0);
 
-  a.SetCornerRadii(RRectF::Corner::kLowerLeft, gfx::Vector2dF(7, 8));
+  a.SetCornerRadii(RRectF::Corner::kLowerLeft, 7, 8);
   CheckRadii(a, 1, 2, 3, 4, 5, 6, 7, 8);
+
+  RRectF b(40, 50, 60, 70, 1, 2, 3, 4, 5, 6, 7, 8);
+  EXPECT_EQ(a, b);
 }
 
 TEST(RRectFTest, FromRectF) {
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index a0df579..eeb70377 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -4,8 +4,6 @@
 
 #include "ui/gl/gl_surface.h"
 
-#include <vector>
-
 #include "base/command_line.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
@@ -80,15 +78,14 @@
   return 0;
 }
 
-void GLSurface::SwapBuffersAsync(
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
+void GLSurface::SwapBuffersAsync(SwapCompletionCallback completion_callback,
+                                 PresentationCallback presentation_callback) {
   NOTREACHED();
 }
 
 gfx::SwapResult GLSurface::SwapBuffersWithBounds(
     const std::vector<gfx::Rect>& rects,
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   return gfx::SwapResult::SWAP_FAILED;
 }
 
@@ -96,29 +93,27 @@
                                          int y,
                                          int width,
                                          int height,
-                                         const PresentationCallback& callback) {
+                                         PresentationCallback callback) {
   return gfx::SwapResult::SWAP_FAILED;
 }
 
-void GLSurface::PostSubBufferAsync(
-    int x,
-    int y,
-    int width,
-    int height,
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
+void GLSurface::PostSubBufferAsync(int x,
+                                   int y,
+                                   int width,
+                                   int height,
+                                   SwapCompletionCallback completion_callback,
+                                   PresentationCallback presentation_callback) {
   NOTREACHED();
 }
 
-gfx::SwapResult GLSurface::CommitOverlayPlanes(
-    const PresentationCallback& callback) {
+gfx::SwapResult GLSurface::CommitOverlayPlanes(PresentationCallback callback) {
   NOTREACHED();
   return gfx::SwapResult::SWAP_FAILED;
 }
 
 void GLSurface::CommitOverlayPlanesAsync(
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
   NOTREACHED();
 }
 
@@ -302,30 +297,29 @@
   return surface_->IsOffscreen();
 }
 
-gfx::SwapResult GLSurfaceAdapter::SwapBuffers(
-    const PresentationCallback& callback) {
-  return surface_->SwapBuffers(callback);
+gfx::SwapResult GLSurfaceAdapter::SwapBuffers(PresentationCallback callback) {
+  return surface_->SwapBuffers(std::move(callback));
 }
 
 void GLSurfaceAdapter::SwapBuffersAsync(
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
-  surface_->SwapBuffersAsync(completion_callback, presentation_callback);
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
+  surface_->SwapBuffersAsync(std::move(completion_callback),
+                             std::move(presentation_callback));
 }
 
 gfx::SwapResult GLSurfaceAdapter::SwapBuffersWithBounds(
     const std::vector<gfx::Rect>& rects,
-    const PresentationCallback& callback) {
-  return surface_->SwapBuffersWithBounds(rects, callback);
+    PresentationCallback callback) {
+  return surface_->SwapBuffersWithBounds(rects, std::move(callback));
 }
 
-gfx::SwapResult GLSurfaceAdapter::PostSubBuffer(
-    int x,
-    int y,
-    int width,
-    int height,
-    const PresentationCallback& callback) {
-  return surface_->PostSubBuffer(x, y, width, height, callback);
+gfx::SwapResult GLSurfaceAdapter::PostSubBuffer(int x,
+                                                int y,
+                                                int width,
+                                                int height,
+                                                PresentationCallback callback) {
+  return surface_->PostSubBuffer(x, y, width, height, std::move(callback));
 }
 
 void GLSurfaceAdapter::PostSubBufferAsync(
@@ -333,22 +327,23 @@
     int y,
     int width,
     int height,
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
-  surface_->PostSubBufferAsync(x, y, width, height, completion_callback,
-                               presentation_callback);
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
+  surface_->PostSubBufferAsync(x, y, width, height,
+                               std::move(completion_callback),
+                               std::move(presentation_callback));
 }
 
 gfx::SwapResult GLSurfaceAdapter::CommitOverlayPlanes(
-    const PresentationCallback& callback) {
-  return surface_->CommitOverlayPlanes(callback);
+    PresentationCallback callback) {
+  return surface_->CommitOverlayPlanes(std::move(callback));
 }
 
 void GLSurfaceAdapter::CommitOverlayPlanesAsync(
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
-  surface_->CommitOverlayPlanesAsync(completion_callback,
-                                     presentation_callback);
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
+  surface_->CommitOverlayPlanesAsync(std::move(completion_callback),
+                                     std::move(presentation_callback));
 }
 
 bool GLSurfaceAdapter::SupportsPresentationCallback() {
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index b21b2e49..5b278bdf 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -6,6 +6,7 @@
 #define UI_GL_GL_SURFACE_H_
 
 #include <string>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -96,11 +97,11 @@
   // |PresentationCallback| will be called.
   // See |PresentationFeedback| for detail.
   using PresentationCallback =
-      base::Callback<void(const gfx::PresentationFeedback& feedback)>;
+      base::OnceCallback<void(const gfx::PresentationFeedback& feedback)>;
 
   // Swaps front and back buffers. This has no effect for off-screen
   // contexts.
-  virtual gfx::SwapResult SwapBuffers(const PresentationCallback& callback) = 0;
+  virtual gfx::SwapResult SwapBuffers(PresentationCallback callback) = 0;
 
   // Get the size of the surface.
   virtual gfx::Size GetSize() = 0;
@@ -139,46 +140,43 @@
   // progress when this callback is invoked, and the signaling of the gpu fence
   // will mark the completion of the swap operation.
   using SwapCompletionCallback =
-      base::Callback<void(gfx::SwapResult, std::unique_ptr<gfx::GpuFence>)>;
+      base::OnceCallback<void(gfx::SwapResult, std::unique_ptr<gfx::GpuFence>)>;
   // Swaps front and back buffers. This has no effect for off-screen
   // contexts. On some platforms, we want to send SwapBufferAck only after the
   // surface is displayed on screen. The callback can be used to delay sending
   // SwapBufferAck till that data is available. The callback should be run on
   // the calling thread (i.e. same thread SwapBuffersAsync is called)
-  virtual void SwapBuffersAsync(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback);
+  virtual void SwapBuffersAsync(SwapCompletionCallback completion_callback,
+                                PresentationCallback presentation_callback);
 
   // Swap buffers with content bounds.
   virtual gfx::SwapResult SwapBuffersWithBounds(
       const std::vector<gfx::Rect>& rects,
-      const PresentationCallback& callback);
+      PresentationCallback callback);
 
   // Copy part of the backbuffer to the frontbuffer.
   virtual gfx::SwapResult PostSubBuffer(int x,
                                         int y,
                                         int width,
                                         int height,
-                                        const PresentationCallback& callback);
+                                        PresentationCallback callback);
 
   // Copy part of the backbuffer to the frontbuffer. On some platforms, we want
   // to send SwapBufferAck only after the surface is displayed on screen. The
   // callback can be used to delay sending SwapBufferAck till that data is
   // available. The callback should be run on the calling thread (i.e. same
   // thread PostSubBufferAsync is called)
-  virtual void PostSubBufferAsync(
-      int x,
-      int y,
-      int width,
-      int height,
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback);
+  virtual void PostSubBufferAsync(int x,
+                                  int y,
+                                  int width,
+                                  int height,
+                                  SwapCompletionCallback completion_callback,
+                                  PresentationCallback presentation_callback);
 
   // Show overlay planes but don't swap the front and back buffers. This acts
   // like SwapBuffers from the point of view of the client, but is cheaper when
   // overlays account for all the damage.
-  virtual gfx::SwapResult CommitOverlayPlanes(
-      const PresentationCallback& callback);
+  virtual gfx::SwapResult CommitOverlayPlanes(PresentationCallback callback);
 
   // Show overlay planes but don't swap the front and back buffers. On some
   // platforms, we want to send SwapBufferAck only after the overlays are
@@ -186,8 +184,8 @@
   // SwapBufferAck till that data is available. The callback should be run on
   // the calling thread (i.e. same thread CommitOverlayPlanesAsync is called).
   virtual void CommitOverlayPlanesAsync(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback);
+      SwapCompletionCallback completion_callback,
+      PresentationCallback presentation_callback);
 
   // Called after a context is made current with this surface. Returns false
   // on error.
@@ -333,30 +331,26 @@
   bool Recreate() override;
   bool DeferDraws() override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
-  void SwapBuffersAsync(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
-  gfx::SwapResult SwapBuffersWithBounds(
-      const std::vector<gfx::Rect>& rects,
-      const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
+  void SwapBuffersAsync(SwapCompletionCallback completion_callback,
+                        PresentationCallback presentation_callback) override;
+  gfx::SwapResult SwapBuffersWithBounds(const std::vector<gfx::Rect>& rects,
+                                        PresentationCallback callback) override;
   gfx::SwapResult PostSubBuffer(int x,
                                 int y,
                                 int width,
                                 int height,
-                                const PresentationCallback& callback) override;
-  void PostSubBufferAsync(
-      int x,
-      int y,
-      int width,
-      int height,
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
-  gfx::SwapResult CommitOverlayPlanes(
-      const PresentationCallback& callback) override;
+                                PresentationCallback callback) override;
+  void PostSubBufferAsync(int x,
+                          int y,
+                          int width,
+                          int height,
+                          SwapCompletionCallback completion_callback,
+                          PresentationCallback presentation_callback) override;
+  gfx::SwapResult CommitOverlayPlanes(PresentationCallback callback) override;
   void CommitOverlayPlanesAsync(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
+      SwapCompletionCallback completion_callback,
+      PresentationCallback presentation_callback) override;
   bool SupportsPresentationCallback() override;
   bool SupportsSwapBuffersWithBounds() override;
   bool SupportsPostSubBuffer() override;
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index 3e61b5f..5e61ed4 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -1199,7 +1199,7 @@
 }
 
 gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
       "width", GetSize().width(),
       "height", GetSize().height());
@@ -1219,7 +1219,7 @@
     new_frame_id = -1;
 
   GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
-      presentation_helper_.get(), callback, new_frame_id);
+      presentation_helper_.get(), std::move(callback), new_frame_id);
 
   if (!eglSwapBuffers(GetDisplay(), surface_)) {
     DVLOG(1) << "eglSwapBuffers failed with error "
@@ -1500,7 +1500,7 @@
 
 gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffersWithDamage(
     const std::vector<int>& rects,
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   DCHECK(supports_swap_buffer_with_damage_);
   if (!CommitAndClearPendingOverlays()) {
     DVLOG(1) << "Failed to commit pending overlay planes.";
@@ -1508,7 +1508,7 @@
   }
 
   GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
-      presentation_helper_.get(), callback);
+      presentation_helper_.get(), std::move(callback));
   if (!eglSwapBuffersWithDamageKHR(GetDisplay(), surface_,
                                    const_cast<EGLint*>(rects.data()),
                                    static_cast<EGLint>(rects.size() / 4))) {
@@ -1524,7 +1524,7 @@
     int y,
     int width,
     int height,
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   DCHECK(supports_post_sub_buffer_);
   if (!CommitAndClearPendingOverlays()) {
     DVLOG(1) << "Failed to commit pending overlay planes.";
@@ -1538,7 +1538,7 @@
   }
 
   GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
-      presentation_helper_.get(), callback);
+      presentation_helper_.get(), std::move(callback));
   if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
     DVLOG(1) << "eglPostSubBufferNV failed with error "
              << GetLastEGLErrorString();
@@ -1556,13 +1556,13 @@
 }
 
 gfx::SwapResult NativeViewGLSurfaceEGL::CommitOverlayPlanes(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   DCHECK(SupportsCommitOverlayPlanes());
   // Here we assume that the overlays scheduled on this surface will display
   // themselves to the screen right away in |CommitAndClearPendingOverlays|,
   // rather than being queued and waiting for a "swap" signal.
   GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
-      presentation_helper_.get(), callback);
+      presentation_helper_.get(), std::move(callback));
   if (!CommitAndClearPendingOverlays())
     scoped_swap_buffers.set_result(gfx::SwapResult::SWAP_FAILED);
   return scoped_swap_buffers.result();
@@ -1697,7 +1697,7 @@
 }
 
 gfx::SwapResult PbufferGLSurfaceEGL::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
   return gfx::SwapResult::SWAP_FAILED;
 }
@@ -1773,8 +1773,7 @@
   return true;
 }
 
-gfx::SwapResult SurfacelessEGL::SwapBuffers(
-    const PresentationCallback& callback) {
+gfx::SwapResult SurfacelessEGL::SwapBuffers(PresentationCallback callback) {
   LOG(ERROR) << "Attempted to call SwapBuffers with SurfacelessEGL.";
   return gfx::SwapResult::SWAP_FAILED;
 }
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h
index 5f740e3..7803daa7 100644
--- a/ui/gl/gl_surface_egl.h
+++ b/ui/gl/gl_surface_egl.h
@@ -122,7 +122,7 @@
               bool has_alpha) override;
   bool Recreate() override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::Size GetSize() override;
   EGLSurface GetHandle() override;
   bool SupportsPostSubBuffer() override;
@@ -130,10 +130,9 @@
                                 int y,
                                 int width,
                                 int height,
-                                const PresentationCallback& callback) override;
+                                PresentationCallback callback) override;
   bool SupportsCommitOverlayPlanes() override;
-  gfx::SwapResult CommitOverlayPlanes(
-      const PresentationCallback& callback) override;
+  gfx::SwapResult CommitOverlayPlanes(PresentationCallback callback) override;
   bool OnMakeCurrent(GLContext* context) override;
   gfx::VSyncProvider* GetVSyncProvider() override;
   void SetVSyncEnabled(bool enabled) override;
@@ -166,7 +165,7 @@
   bool enable_fixed_size_angle_ = true;
 
   gfx::SwapResult SwapBuffersWithDamage(const std::vector<int>& rects,
-                                        const PresentationCallback& callback);
+                                        PresentationCallback callback);
 
  private:
   struct SwapInfo {
@@ -221,7 +220,7 @@
   bool Initialize(GLSurfaceFormat format) override;
   void Destroy() override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::Size GetSize() override;
   bool Resize(const gfx::Size& size,
               float scale_factor,
@@ -252,7 +251,7 @@
   void Destroy() override;
   bool IsOffscreen() override;
   bool IsSurfaceless() const override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::Size GetSize() override;
   bool Resize(const gfx::Size& size,
               float scale_factor,
diff --git a/ui/gl/gl_surface_egl_surface_control.cc b/ui/gl/gl_surface_egl_surface_control.cc
index e617b2a..4df26ab 100644
--- a/ui/gl/gl_surface_egl_surface_control.cc
+++ b/ui/gl/gl_surface_egl_surface_control.cc
@@ -4,6 +4,8 @@
 
 #include "ui/gl/gl_surface_egl_surface_control.h"
 
+#include <utility>
+
 #include "base/android/android_hardware_buffer_compat.h"
 #include "base/android/scoped_hardware_buffer_fence_sync.h"
 #include "base/bind.h"
@@ -64,32 +66,34 @@
 }
 
 gfx::SwapResult GLSurfaceEGLSurfaceControl::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   NOTREACHED();
   return gfx::SwapResult::SWAP_FAILED;
 }
 
 void GLSurfaceEGLSurfaceControl::SwapBuffersAsync(
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
-  CommitPendingTransaction(completion_callback, presentation_callback);
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
+  CommitPendingTransaction(std::move(completion_callback),
+                           std::move(presentation_callback));
 }
 
 gfx::SwapResult GLSurfaceEGLSurfaceControl::CommitOverlayPlanes(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   NOTREACHED();
   return gfx::SwapResult::SWAP_FAILED;
 }
 
 void GLSurfaceEGLSurfaceControl::CommitOverlayPlanesAsync(
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
-  CommitPendingTransaction(completion_callback, presentation_callback);
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
+  CommitPendingTransaction(std::move(completion_callback),
+                           std::move(presentation_callback));
 }
 
 void GLSurfaceEGLSurfaceControl::CommitPendingTransaction(
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& present_callback) {
+    SwapCompletionCallback completion_callback,
+    PresentationCallback present_callback) {
   DCHECK(pending_transaction_);
 
   // Release resources for the current frame once the next frame is acked.
@@ -101,10 +105,10 @@
   current_frame_resources_.swap(pending_frame_resources_);
   pending_frame_resources_.clear();
 
-  SurfaceControl::Transaction::OnCompleteCb callback =
-      base::BindOnce(&GLSurfaceEGLSurfaceControl::OnTransactionAckOnGpuThread,
-                     weak_factory_.GetWeakPtr(), completion_callback,
-                     present_callback, std::move(resources_to_release));
+  SurfaceControl::Transaction::OnCompleteCb callback = base::BindOnce(
+      &GLSurfaceEGLSurfaceControl::OnTransactionAckOnGpuThread,
+      weak_factory_.GetWeakPtr(), std::move(completion_callback),
+      std::move(present_callback), std::move(resources_to_release));
   pending_transaction_->SetOnCompleteCb(std::move(callback), gpu_task_runner_);
 
   pending_transaction_->Apply();
@@ -246,14 +250,14 @@
   context_->MakeCurrent(this);
 
   // The presentation feedback callback must run after swap completion.
-  completion_callback.Run(gfx::SwapResult::SWAP_ACK, nullptr);
+  std::move(completion_callback).Run(gfx::SwapResult::SWAP_ACK, nullptr);
 
   // TODO(khushalsagar): Maintain a queue of present fences so we poll to see if
   // they are signaled every frame, and get a signal timestamp to feed into this
   // feedback.
   gfx::PresentationFeedback feedback(base::TimeTicks::Now(), base::TimeDelta(),
                                      0 /* flags */);
-  presentation_callback.Run(feedback);
+  std::move(presentation_callback).Run(feedback);
 
   for (auto& surface_stat : transaction_stats.surface_stats) {
     auto it = released_resources.find(surface_stat.surface);
diff --git a/ui/gl/gl_surface_egl_surface_control.h b/ui/gl/gl_surface_egl_surface_control.h
index ca7b9f08..6a7ab0a 100644
--- a/ui/gl/gl_surface_egl_surface_control.h
+++ b/ui/gl/gl_surface_egl_surface_control.h
@@ -41,15 +41,13 @@
               ColorSpace color_space,
               bool has_alpha) override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
-  void SwapBuffersAsync(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
-  gfx::SwapResult CommitOverlayPlanes(
-      const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
+  void SwapBuffersAsync(SwapCompletionCallback completion_callback,
+                        PresentationCallback presentation_callback) override;
+  gfx::SwapResult CommitOverlayPlanes(PresentationCallback callback) override;
   void CommitOverlayPlanesAsync(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
+      SwapCompletionCallback completion_callback,
+      PresentationCallback presentation_callback) override;
   gfx::Size GetSize() override;
   bool OnMakeCurrent(GLContext* context) override;
   bool ScheduleOverlayPlane(int z_order,
@@ -101,9 +99,8 @@
   };
   using ResourceRefs = base::flat_map<ASurfaceControl*, ResourceRef>;
 
-  void CommitPendingTransaction(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& callback);
+  void CommitPendingTransaction(SwapCompletionCallback completion_callback,
+                                PresentationCallback callback);
 
   // Called on the |gpu_task_runner_| when a transaction is acked by the
   // framework.
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc
index fd7041f..2eab605a 100644
--- a/ui/gl/gl_surface_glx.cc
+++ b/ui/gl/gl_surface_glx.cc
@@ -4,7 +4,7 @@
 
 #include "ui/gl/gl_surface_glx.h"
 
-#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -675,11 +675,11 @@
 }
 
 gfx::SwapResult NativeViewGLSurfaceGLX::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers", "width",
                GetSize().width(), "height", GetSize().height());
   GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
-      presentation_helper_.get(), callback);
+      presentation_helper_.get(), std::move(callback));
 
   XDisplay* display = gfx::GetXDisplay();
   glXSwapBuffers(display, GetDrawableHandle());
@@ -731,11 +731,11 @@
     int y,
     int width,
     int height,
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   DCHECK(g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer);
 
   GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
-      presentation_helper_.get(), callback);
+      presentation_helper_.get(), std::move(callback));
   glXCopySubBufferMESA(gfx::GetXDisplay(), GetDrawableHandle(), x, y, width,
                        height);
   return scoped_swap_buffers.result();
@@ -837,7 +837,7 @@
 }
 
 gfx::SwapResult UnmappedNativeViewGLSurfaceGLX::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   NOTREACHED() << "Attempted to call SwapBuffers on an unmapped window.";
   return gfx::SwapResult::SWAP_FAILED;
 }
diff --git a/ui/gl/gl_surface_glx.h b/ui/gl/gl_surface_glx.h
index cfcb2f3..35e3720 100644
--- a/ui/gl/gl_surface_glx.h
+++ b/ui/gl/gl_surface_glx.h
@@ -78,7 +78,7 @@
               ColorSpace color_space,
               bool has_alpha) override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::Size GetSize() override;
   void* GetHandle() override;
   bool SupportsPresentationCallback() override;
@@ -90,7 +90,7 @@
                                 int y,
                                 int width,
                                 int height,
-                                const PresentationCallback& callback) override;
+                                PresentationCallback callback) override;
   bool OnMakeCurrent(GLContext* context) override;
   gfx::VSyncProvider* GetVSyncProvider() override;
   void SetVSyncEnabled(bool enabled) override;
@@ -147,7 +147,7 @@
   bool Initialize(GLSurfaceFormat format) override;
   void Destroy() override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::Size GetSize() override;
   void* GetHandle() override;
   void* GetConfig() override;
diff --git a/ui/gl/gl_surface_presentation_helper.cc b/ui/gl/gl_surface_presentation_helper.cc
index aa35cf4..987725c 100644
--- a/ui/gl/gl_surface_presentation_helper.cc
+++ b/ui/gl/gl_surface_presentation_helper.cc
@@ -4,6 +4,8 @@
 
 #include "ui/gl/gl_surface_presentation_helper.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -17,16 +19,16 @@
 
 GLSurfacePresentationHelper::ScopedSwapBuffers::ScopedSwapBuffers(
     GLSurfacePresentationHelper* helper,
-    const GLSurface::PresentationCallback& callback)
-    : ScopedSwapBuffers(helper, callback, -1) {}
+    GLSurface::PresentationCallback callback)
+    : ScopedSwapBuffers(helper, std::move(callback), -1) {}
 
 GLSurfacePresentationHelper::ScopedSwapBuffers::ScopedSwapBuffers(
     GLSurfacePresentationHelper* helper,
-    const GLSurface::PresentationCallback& callback,
+    GLSurface::PresentationCallback callback,
     int frame_id)
     : helper_(helper) {
   if (helper_)
-    helper_->PreSwapBuffers(callback, frame_id);
+    helper_->PreSwapBuffers(std::move(callback), frame_id);
 }
 
 GLSurfacePresentationHelper::ScopedSwapBuffers::~ScopedSwapBuffers() {
@@ -38,22 +40,22 @@
 
 GLSurfacePresentationHelper::Frame::Frame(
     int frame_id,
-    const GLSurface::PresentationCallback& callback)
-    : frame_id(frame_id), callback(callback) {}
+    GLSurface::PresentationCallback callback)
+    : frame_id(frame_id), callback(std::move(callback)) {}
 
 GLSurfacePresentationHelper::Frame::Frame(
     std::unique_ptr<GPUTimer>&& timer,
-    const GLSurface::PresentationCallback& callback)
-    : timer(std::move(timer)), callback(callback) {}
+    GLSurface::PresentationCallback callback)
+    : timer(std::move(timer)), callback(std::move(callback)) {}
 
 GLSurfacePresentationHelper::Frame::Frame(
     std::unique_ptr<GLFence>&& fence,
-    const GLSurface::PresentationCallback& callback)
-    : fence(std::move(fence)), callback(callback) {}
+    GLSurface::PresentationCallback callback)
+    : fence(std::move(fence)), callback(std::move(callback)) {}
 
 GLSurfacePresentationHelper::Frame::Frame(
-    const GLSurface::PresentationCallback& callback)
-    : callback(callback) {}
+    GLSurface::PresentationCallback callback)
+    : callback(std::move(callback)) {}
 
 GLSurfacePresentationHelper::Frame::~Frame() = default;
 
@@ -132,7 +134,7 @@
     else
       fence->Invalidate();
   }
-  callback.Run(gfx::PresentationFeedback::Failure());
+  std::move(callback).Run(gfx::PresentationFeedback::Failure());
 }
 
 GLSurfacePresentationHelper::GLSurfacePresentationHelper(
@@ -202,20 +204,20 @@
 }
 
 void GLSurfacePresentationHelper::PreSwapBuffers(
-    const GLSurface::PresentationCallback& callback,
+    GLSurface::PresentationCallback callback,
     int frame_id) {
   if (egl_timestamp_client_) {
-    pending_frames_.emplace_back(frame_id, callback);
+    pending_frames_.emplace_back(frame_id, std::move(callback));
   } else if (gpu_timing_client_) {
     std::unique_ptr<GPUTimer> timer;
     timer = gpu_timing_client_->CreateGPUTimer(false /* prefer_elapsed_time */);
     timer->QueryTimeStamp();
-    pending_frames_.push_back(Frame(std::move(timer), callback));
+    pending_frames_.push_back(Frame(std::move(timer), std::move(callback)));
   } else if (gl_fence_supported_) {
     auto fence = GLFence::Create();
-    pending_frames_.push_back(Frame(std::move(fence), callback));
+    pending_frames_.push_back(Frame(std::move(fence), std::move(callback)));
   } else {
-    pending_frames_.push_back(Frame(callback));
+    pending_frames_.push_back(Frame(std::move(callback)));
   }
 }
 
@@ -271,9 +273,9 @@
       if (frame.timer)
         frame.timer->Destroy(true /* has_context */);
       if (frame.result == gfx::SwapResult::SWAP_ACK)
-        frame.callback.Run(feedback);
+        std::move(frame.callback).Run(feedback);
       else
-        frame.callback.Run(gfx::PresentationFeedback::Failure());
+        std::move(frame.callback).Run(gfx::PresentationFeedback::Failure());
     }
     pending_frames_.clear();
     // We want to update VSync, if we can not get VSync parameters
@@ -293,7 +295,7 @@
         [this, &frame](const gfx::PresentationFeedback& feedback) {
           if (frame.timer)
             frame.timer->Destroy(true /* has_context */);
-          frame.callback.Run(feedback);
+          std::move(frame.callback).Run(feedback);
           pending_frames_.pop_front();
         };
 
diff --git a/ui/gl/gl_surface_presentation_helper.h b/ui/gl/gl_surface_presentation_helper.h
index 5162891..482b478d 100644
--- a/ui/gl/gl_surface_presentation_helper.h
+++ b/ui/gl/gl_surface_presentation_helper.h
@@ -31,9 +31,9 @@
   class GL_EXPORT ScopedSwapBuffers {
    public:
     ScopedSwapBuffers(GLSurfacePresentationHelper* helper,
-                      const GLSurface::PresentationCallback& callback);
+                      GLSurface::PresentationCallback callback);
     ScopedSwapBuffers(GLSurfacePresentationHelper* helper,
-                      const GLSurface::PresentationCallback& callback,
+                      GLSurface::PresentationCallback callback,
                       int frame_id);
     ~ScopedSwapBuffers();
 
@@ -55,19 +55,18 @@
   ~GLSurfacePresentationHelper();
 
   void OnMakeCurrent(GLContext* context, GLSurface* surface);
-  void PreSwapBuffers(const GLSurface::PresentationCallback& callback,
-                      int frame_id);
+  void PreSwapBuffers(GLSurface::PresentationCallback callback, int frame_id);
   void PostSwapBuffers(gfx::SwapResult result);
 
  private:
   struct Frame {
     Frame(Frame&& other);
-    Frame(int frame_id, const GLSurface::PresentationCallback& callback);
+    Frame(int frame_id, GLSurface::PresentationCallback callback);
     Frame(std::unique_ptr<GPUTimer>&& timer,
-          const GLSurface::PresentationCallback& callback);
+          GLSurface::PresentationCallback callback);
     Frame(std::unique_ptr<GLFence>&& fence,
-          const GLSurface::PresentationCallback& callback);
-    Frame(const GLSurface::PresentationCallback& callback);
+          GLSurface::PresentationCallback callback);
+    explicit Frame(GLSurface::PresentationCallback callback);
     ~Frame();
     Frame& operator=(Frame&& other);
 
diff --git a/ui/gl/gl_surface_stub.cc b/ui/gl/gl_surface_stub.cc
index 3b6dba49..8eb6a18b 100644
--- a/ui/gl/gl_surface_stub.cc
+++ b/ui/gl/gl_surface_stub.cc
@@ -4,6 +4,8 @@
 
 #include "ui/gl/gl_surface_stub.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -24,12 +26,11 @@
   return false;
 }
 
-gfx::SwapResult GLSurfaceStub::SwapBuffers(
-    const PresentationCallback& callback) {
+gfx::SwapResult GLSurfaceStub::SwapBuffers(PresentationCallback callback) {
   gfx::PresentationFeedback feedback(base::TimeTicks::Now(), base::TimeDelta(),
                                      0 /* flags */);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(callback, std::move(feedback)));
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(feedback)));
   return gfx::SwapResult::SWAP_ACK;
 }
 
diff --git a/ui/gl/gl_surface_stub.h b/ui/gl/gl_surface_stub.h
index c3db1fb..65a544b 100644
--- a/ui/gl/gl_surface_stub.h
+++ b/ui/gl/gl_surface_stub.h
@@ -27,7 +27,7 @@
               ColorSpace color_space,
               bool has_alpha) override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::Size GetSize() override;
   void* GetHandle() override;
   bool BuffersFlipped() const override;
diff --git a/ui/gl/gl_surface_wgl.cc b/ui/gl/gl_surface_wgl.cc
index 978b5a7..b0b3b1c 100644
--- a/ui/gl/gl_surface_wgl.cc
+++ b/ui/gl/gl_surface_wgl.cc
@@ -5,6 +5,7 @@
 #include "ui/gl/gl_surface_wgl.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/logging.h"
 #include "base/trace_event/trace_event.h"
@@ -290,7 +291,7 @@
 }
 
 gfx::SwapResult NativeViewGLSurfaceWGL::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   // TODO(penghuang): Provide presentation feedback. https://crbug.com/776877
   TRACE_EVENT2("gpu", "NativeViewGLSurfaceWGL:RealSwapBuffers",
       "width", GetSize().width(),
@@ -315,13 +316,13 @@
     // TODO(penghuang): Provide more accurate values for presentation feedback.
     constexpr int64_t kRefreshIntervalInMicroseconds =
         base::Time::kMicrosecondsPerSecond / 60;
-    callback.Run(gfx::PresentationFeedback(
+    std::move(callback).Run(gfx::PresentationFeedback(
         base::TimeTicks::Now(),
         base::TimeDelta::FromMicroseconds(kRefreshIntervalInMicroseconds),
         0 /* flags */));
     return gfx::SwapResult::SWAP_ACK;
   } else {
-    callback.Run(gfx::PresentationFeedback::Failure());
+    std::move(callback).Run(gfx::PresentationFeedback::Failure());
     return gfx::SwapResult::SWAP_FAILED;
   }
 }
@@ -416,7 +417,7 @@
 }
 
 gfx::SwapResult PbufferGLSurfaceWGL::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
   return gfx::SwapResult::SWAP_FAILED;
 }
diff --git a/ui/gl/gl_surface_wgl.h b/ui/gl/gl_surface_wgl.h
index fac4036..ce60da2 100644
--- a/ui/gl/gl_surface_wgl.h
+++ b/ui/gl/gl_surface_wgl.h
@@ -47,7 +47,7 @@
               bool has_alpha) override;
   bool Recreate() override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::Size GetSize() override;
   void* GetHandle() override;
   GLSurfaceFormat GetFormat() override;
@@ -76,7 +76,7 @@
   bool Initialize(GLSurfaceFormat format) override;
   void Destroy() override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   gfx::Size GetSize() override;
   void* GetHandle() override;
   GLSurfaceFormat GetFormat() override;
diff --git a/ui/gl/init/gl_factory_mac.cc b/ui/gl/init/gl_factory_mac.cc
index a084ec6..56b8916 100644
--- a/ui/gl/init/gl_factory_mac.cc
+++ b/ui/gl/init/gl_factory_mac.cc
@@ -39,7 +39,7 @@
   bool Initialize(GLSurfaceFormat format) override { return true; }
   void Destroy() override {}
   bool IsOffscreen() override { return true; }
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override {
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override {
     NOTREACHED() << "Cannot call SwapBuffers on a NoOpGLSurface.";
     return gfx::SwapResult::SWAP_FAILED;
   }
diff --git a/ui/ozone/common/gl_surface_egl_readback.cc b/ui/ozone/common/gl_surface_egl_readback.cc
index 0a64d5b..963582357 100644
--- a/ui/ozone/common/gl_surface_egl_readback.cc
+++ b/ui/ozone/common/gl_surface_egl_readback.cc
@@ -42,7 +42,7 @@
 }
 
 gfx::SwapResult GLSurfaceEglReadback::SwapBuffers(
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   const gfx::Size size = GetSize();
   glReadPixels(0, 0, size.width(), size.height(), GL_BGRA, GL_UNSIGNED_BYTE,
                pixels_.get());
diff --git a/ui/ozone/common/gl_surface_egl_readback.h b/ui/ozone/common/gl_surface_egl_readback.h
index aa9240c..2e8f25a 100644
--- a/ui/ozone/common/gl_surface_egl_readback.h
+++ b/ui/ozone/common/gl_surface_egl_readback.h
@@ -31,7 +31,7 @@
               ColorSpace color_space,
               bool has_alpha) override;
   bool IsOffscreen() override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   bool SupportsPresentationCallback() override;
   bool FlipsVertically() const override;
 
diff --git a/ui/ozone/demo/demo_window.cc b/ui/ozone/demo/demo_window.cc
index 0915cd0..f376744 100644
--- a/ui/ozone/demo/demo_window.cc
+++ b/ui/ozone/demo/demo_window.cc
@@ -15,10 +15,7 @@
 #include "ui/platform_window/platform_window_init_properties.h"
 
 #if defined(OS_FUCHSIA)
-#include <fuchsia/ui/policy/cpp/fidl.h>
-#include <lib/zx/eventpair.h>
-#include "base/fuchsia/component_context.h"
-#include "base/fuchsia/fuchsia_logging.h"
+#include "ui/platform_window/fuchsia/initialize_presenter_api_view.h"
 #endif
 
 namespace ui {
@@ -38,17 +35,7 @@
   if (ui::OzonePlatform::GetInstance()
           ->GetPlatformProperties()
           .needs_view_token) {
-    // Create view_token and view_holder_token.
-    zx::eventpair view_holder_token;
-    zx_status_t status = zx::eventpair::create(
-        /*options=*/0, &properties.view_token, &view_holder_token);
-    ZX_CHECK(status == ZX_OK, status) << "zx_eventpair_create";
-
-    // Request Presenter to show the view full-screen.
-    auto presenter = base::fuchsia::ComponentContext::GetDefault()
-                         ->ConnectToService<fuchsia::ui::policy::Presenter>();
-
-    presenter->Present2(std::move(view_holder_token), nullptr);
+    ui::fuchsia::InitializeViewTokenAndPresentView(&properties);
   }
 #endif
 
diff --git a/ui/ozone/demo/gl_renderer.cc b/ui/ozone/demo/gl_renderer.cc
index 192fcc44..2003489 100644
--- a/ui/ozone/demo/gl_renderer.cc
+++ b/ui/ozone/demo/gl_renderer.cc
@@ -55,14 +55,14 @@
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
   if (surface_->SupportsAsyncSwap()) {
-    surface_->SwapBuffersAsync(base::Bind(&GlRenderer::PostRenderFrameTask,
-                                          weak_ptr_factory_.GetWeakPtr()),
-                               base::Bind(&GlRenderer::OnPresentation,
-                                          weak_ptr_factory_.GetWeakPtr()));
+    surface_->SwapBuffersAsync(base::BindOnce(&GlRenderer::PostRenderFrameTask,
+                                              weak_ptr_factory_.GetWeakPtr()),
+                               base::BindOnce(&GlRenderer::OnPresentation,
+                                              weak_ptr_factory_.GetWeakPtr()));
   } else {
     PostRenderFrameTask(
-        surface_->SwapBuffers(base::Bind(&GlRenderer::OnPresentation,
-                                         weak_ptr_factory_.GetWeakPtr())),
+        surface_->SwapBuffers(base::BindOnce(&GlRenderer::OnPresentation,
+                                             weak_ptr_factory_.GetWeakPtr())),
         nullptr);
   }
 }
diff --git a/ui/ozone/platform/cast/gl_surface_cast.cc b/ui/ozone/platform/cast/gl_surface_cast.cc
index 87f8753f..3378fd0 100644
--- a/ui/ozone/platform/cast/gl_surface_cast.cc
+++ b/ui/ozone/platform/cast/gl_surface_cast.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/cast/gl_surface_cast.h"
 
 #include <string>
+#include <utility>
 
 #include "base/feature_list.h"
 #include "base/strings/string_number_conversions.h"
@@ -62,7 +63,7 @@
 
 gfx::SwapResult GLSurfaceCast::SwapBuffersWithBounds(
     const std::vector<gfx::Rect>& rects,
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   DCHECK(supports_swap_buffer_with_bounds_);
 
   // TODO(halliwell): Request new EGL extension so we're not abusing
@@ -75,7 +76,8 @@
     rects_data[i * 4 + 3] = rects[i].height();
   }
 
-  return NativeViewGLSurfaceEGL::SwapBuffersWithDamage(rects_data, callback);
+  return NativeViewGLSurfaceEGL::SwapBuffersWithDamage(rects_data,
+                                                       std::move(callback));
 }
 
 bool GLSurfaceCast::Resize(const gfx::Size& size,
diff --git a/ui/ozone/platform/cast/gl_surface_cast.h b/ui/ozone/platform/cast/gl_surface_cast.h
index ad62de08..e8d88a6f 100644
--- a/ui/ozone/platform/cast/gl_surface_cast.h
+++ b/ui/ozone/platform/cast/gl_surface_cast.h
@@ -25,9 +25,8 @@
 
   // gl::GLSurface:
   bool SupportsSwapBuffersWithBounds() override;
-  gfx::SwapResult SwapBuffersWithBounds(
-      const std::vector<gfx::Rect>& rects,
-      const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffersWithBounds(const std::vector<gfx::Rect>& rects,
+                                        PresentationCallback callback) override;
   bool Resize(const gfx::Size& size,
               float scale_factor,
               ColorSpace color_space,
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index e359f6a..66d000a 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -56,8 +56,7 @@
   return true;
 }
 
-gfx::SwapResult GbmSurfaceless::SwapBuffers(
-    const PresentationCallback& callback) {
+gfx::SwapResult GbmSurfaceless::SwapBuffers(PresentationCallback callback) {
   NOTREACHED();
   return gfx::SwapResult::SWAP_FAILED;
 }
@@ -96,26 +95,25 @@
   return supports_plane_gpu_fences_;
 }
 
-gfx::SwapResult GbmSurfaceless::PostSubBuffer(
-    int x,
-    int y,
-    int width,
-    int height,
-    const PresentationCallback& callback) {
+gfx::SwapResult GbmSurfaceless::PostSubBuffer(int x,
+                                              int y,
+                                              int width,
+                                              int height,
+                                              PresentationCallback callback) {
   // The actual sub buffer handling is handled at higher layers.
   NOTREACHED();
   return gfx::SwapResult::SWAP_FAILED;
 }
 
 void GbmSurfaceless::SwapBuffersAsync(
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
   TRACE_EVENT0("drm", "GbmSurfaceless::SwapBuffersAsync");
   // If last swap failed, don't try to schedule new ones.
   if (!last_swap_buffers_result_) {
-    completion_callback.Run(gfx::SwapResult::SWAP_FAILED, nullptr);
+    std::move(completion_callback).Run(gfx::SwapResult::SWAP_FAILED, nullptr);
     // Notify the caller, the buffer is never presented on a screen.
-    presentation_callback.Run(gfx::PresentationFeedback::Failure());
+    std::move(presentation_callback).Run(gfx::PresentationFeedback::Failure());
     return;
   }
 
@@ -125,8 +123,8 @@
   unsubmitted_frames_.back()->Flush();
 
   PendingFrame* frame = unsubmitted_frames_.back().get();
-  frame->completion_callback = completion_callback;
-  frame->presentation_callback = presentation_callback;
+  frame->completion_callback = std::move(completion_callback);
+  frame->presentation_callback = std::move(presentation_callback);
   unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
 
   // TODO(dcastagna): Remove the following workaround once we get explicit sync
@@ -167,10 +165,11 @@
     int y,
     int width,
     int height,
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
   // The actual sub buffer handling is handled at higher layers.
-  SwapBuffersAsync(completion_callback, presentation_callback);
+  SwapBuffersAsync(std::move(completion_callback),
+                   std::move(presentation_callback));
 }
 
 EGLConfig GbmSurfaceless::GetConfig() {
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
index 8923a62..abddcb03 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -36,7 +36,7 @@
 
   // gl::GLSurface:
   bool Initialize(gl::GLSurfaceFormat format) override;
-  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::SwapResult SwapBuffers(PresentationCallback callback) override;
   bool ScheduleOverlayPlane(int z_order,
                             gfx::OverlayTransform transform,
                             gl::GLImage* image,
@@ -53,17 +53,15 @@
                                 int y,
                                 int width,
                                 int height,
-                                const PresentationCallback& callback) override;
-  void SwapBuffersAsync(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
-  void PostSubBufferAsync(
-      int x,
-      int y,
-      int width,
-      int height,
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
+                                PresentationCallback callback) override;
+  void SwapBuffersAsync(SwapCompletionCallback completion_callback,
+                        PresentationCallback presentation_callback) override;
+  void PostSubBufferAsync(int x,
+                          int y,
+                          int width,
+                          int height,
+                          SwapCompletionCallback completion_callback,
+                          PresentationCallback presentation_callback) override;
   EGLConfig GetConfig() override;
   void SetRelyOnImplicitSync() override;
 
diff --git a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
index 2958f64..acf1035 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
@@ -75,21 +75,21 @@
     int y,
     int width,
     int height,
-    const PresentationCallback& callback) {
+    PresentationCallback callback) {
   // The actual sub buffer handling is handled at higher layers.
   NOTREACHED();
   return gfx::SwapResult::SWAP_FAILED;
 }
 
 void GbmSurfacelessWayland::SwapBuffersAsync(
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
   TRACE_EVENT0("wayland", "GbmSurfacelessWayland::SwapBuffersAsync");
   // If last swap failed, don't try to schedule new ones.
   if (!last_swap_buffers_result_) {
-    completion_callback.Run(gfx::SwapResult::SWAP_FAILED, nullptr);
+    std::move(completion_callback).Run(gfx::SwapResult::SWAP_FAILED, nullptr);
     // Notify the caller, the buffer is never presented on a screen.
-    presentation_callback.Run(gfx::PresentationFeedback::Failure());
+    std::move(presentation_callback).Run(gfx::PresentationFeedback::Failure());
     return;
   }
 
@@ -99,8 +99,8 @@
   unsubmitted_frames_.back()->Flush();
 
   PendingFrame* frame = unsubmitted_frames_.back().get();
-  frame->completion_callback = completion_callback;
-  frame->presentation_callback = presentation_callback;
+  frame->completion_callback = std::move(completion_callback);
+  frame->presentation_callback = std::move(presentation_callback);
   unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
 
   // TODO: the following should be replaced by a per surface flush as it gets
@@ -125,12 +125,13 @@
     int y,
     int width,
     int height,
-    const SwapCompletionCallback& completion_callback,
-    const PresentationCallback& presentation_callback) {
+    SwapCompletionCallback completion_callback,
+    PresentationCallback presentation_callback) {
   PendingFrame* frame = unsubmitted_frames_.back().get();
   frame->damage_region_ = gfx::Rect(x, y, width, height);
 
-  SwapBuffersAsync(completion_callback, presentation_callback);
+  SwapBuffersAsync(std::move(completion_callback),
+                   std::move(presentation_callback));
 }
 
 EGLConfig GbmSurfacelessWayland::GetConfig() {
diff --git a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
index bfb8c9f9..89be735 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
+++ b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
@@ -43,17 +43,15 @@
                                 int y,
                                 int width,
                                 int height,
-                                const PresentationCallback& callback) override;
-  void SwapBuffersAsync(
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
-  void PostSubBufferAsync(
-      int x,
-      int y,
-      int width,
-      int height,
-      const SwapCompletionCallback& completion_callback,
-      const PresentationCallback& presentation_callback) override;
+                                PresentationCallback callback) override;
+  void SwapBuffersAsync(SwapCompletionCallback completion_callback,
+                        PresentationCallback presentation_callback) override;
+  void PostSubBufferAsync(int x,
+                          int y,
+                          int width,
+                          int height,
+                          SwapCompletionCallback completion_callback,
+                          PresentationCallback presentation_callback) override;
   EGLConfig GetConfig() override;
 
  private:
diff --git a/ui/views/controls/button/image_button_factory.cc b/ui/views/controls/button/image_button_factory.cc
index 30c082c..479b7a1 100644
--- a/ui/views/controls/button/image_button_factory.cc
+++ b/ui/views/controls/button/image_button_factory.cc
@@ -6,6 +6,7 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/vector_icon_types.h"
+#include "ui/native_theme/native_theme.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/image_button.h"
@@ -39,6 +40,13 @@
   return button;
 }
 
+void SetImageFromVectorIcon(ImageButton* button, const gfx::VectorIcon& icon) {
+  SetImageFromVectorIconWithColor(
+      button, icon,
+      ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
+          ui::NativeTheme::kColorId_DefaultIconColor));
+}
+
 void SetImageFromVectorIcon(ImageButton* button,
                             const gfx::VectorIcon& icon,
                             SkColor related_text_color) {
diff --git a/ui/views/controls/button/image_button_factory.h b/ui/views/controls/button/image_button_factory.h
index 0f407183..94d2dfe 100644
--- a/ui/views/controls/button/image_button_factory.h
+++ b/ui/views/controls/button/image_button_factory.h
@@ -30,20 +30,23 @@
     ButtonListener* listener);
 
 // Sets images on |button| for STATE_NORMAL and STATE_DISABLED from the given
+// vector icon using the default color from the current NativeTheme.
+VIEWS_EXPORT void SetImageFromVectorIcon(ImageButton* button,
+                                         const gfx::VectorIcon& icon);
+
+// Sets images on |button| for STATE_NORMAL and STATE_DISABLED from the given
 // vector icon and color. |related_text_color| is normally the main text color
 // used in the parent view, and the actual color used is derived from that. Call
 // again to update the button if |related_text_color| is changing.
-VIEWS_EXPORT void SetImageFromVectorIcon(
-    ImageButton* button,
-    const gfx::VectorIcon& icon,
-    SkColor related_text_color = gfx::kGoogleGrey900);
+VIEWS_EXPORT void SetImageFromVectorIcon(ImageButton* button,
+                                         const gfx::VectorIcon& icon,
+                                         SkColor related_text_color);
 
 // As above, but creates the images at the given size.
-VIEWS_EXPORT void SetImageFromVectorIcon(
-    ImageButton* button,
-    const gfx::VectorIcon& icon,
-    int dip_size,
-    SkColor related_text_color = gfx::kGoogleGrey900);
+VIEWS_EXPORT void SetImageFromVectorIcon(ImageButton* button,
+                                         const gfx::VectorIcon& icon,
+                                         int dip_size,
+                                         SkColor related_text_color);
 
 // Sets images on |button| for STATE_NORMAL and STATE_DISABLED from the given
 // vector icon and color.
diff --git a/ui/views/controls/button/image_button_factory_unittest.cc b/ui/views/controls/button/image_button_factory_unittest.cc
index f56c56cf..86d85eba 100644
--- a/ui/views/controls/button/image_button_factory_unittest.cc
+++ b/ui/views/controls/button/image_button_factory_unittest.cc
@@ -7,6 +7,7 @@
 #include "components/vector_icons/vector_icons.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
+#include "ui/native_theme/native_theme.h"
 #include "ui/views/animation/test/ink_drop_host_view_test_api.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/image_button.h"
@@ -30,12 +31,15 @@
   EXPECT_FALSE(button->GetImage(Button::STATE_DISABLED).isNull());
   EXPECT_EQ(color_utils::DeriveDefaultIconColor(SK_ColorRED),
             button->GetInkDropBaseColor());
-
-  // Default to GoogleGrey900.
-  SetImageFromVectorIcon(button, vector_icons::kCloseRoundedIcon);
-  EXPECT_EQ(color_utils::DeriveDefaultIconColor(gfx::kGoogleGrey900),
-            button->GetInkDropBaseColor());
   delete button;
 }
 
+TEST_F(ImageButtonFactoryTest, SetImageFromVectorIcon_Default) {
+  ImageButton* button = CreateVectorImageButton(nullptr);
+  SetImageFromVectorIcon(button, vector_icons::kCloseRoundedIcon);
+  EXPECT_EQ(button->GetNativeTheme()->GetSystemColor(
+                ui::NativeTheme::kColorId_DefaultIconColor),
+            button->GetInkDropBaseColor());
+  delete button;
+}
 }  // views
diff --git a/ui/webui/resources/js/cr/ui/array_data_model.js b/ui/webui/resources/js/cr/ui/array_data_model.js
index 4998fc7c..72c3ffb 100644
--- a/ui/webui/resources/js/cr/ui/array_data_model.js
+++ b/ui/webui/resources/js/cr/ui/array_data_model.js
@@ -15,27 +15,27 @@
 // <include src="../../assert.js">
 
 cr.define('cr.ui', function() {
-  /** @const */ const EventTarget = cr.EventTarget;
-
   /**
    * A data model that wraps a simple array and supports sorting by storing
    * initial indexes of elements for each position in sorted array.
-   * @param {!Array} array The underlying array.
-   * @constructor
-   * @extends {cr.EventTarget}
    */
-  function ArrayDataModel(array) {
-    this.array_ = array;
-    this.indexes_ = [];
-    this.compareFunctions_ = {};
+  class ArrayDataModel extends cr.EventTarget {
+    /**
+     * @param {!Array} array The underlying array.
+     */
+    constructor(array) {
+      super();
+      this.array_ = array;
+      this.indexes_ = [];
+      this.compareFunctions_ = {};
 
-    for (let i = 0; i < array.length; i++) {
-      this.indexes_.push(i);
+      /** @type {?Object} */
+      this.sortStatus_;
+
+      for (let i = 0; i < array.length; i++) {
+        this.indexes_.push(i);
+      }
     }
-  }
-
-  ArrayDataModel.prototype = {
-    __proto__: EventTarget.prototype,
 
     /**
      * The length of the data model.
@@ -43,7 +43,7 @@
      */
     get length() {
       return this.array_.length;
-    },
+    }
 
     /**
      * Returns the item at the given index.
@@ -52,21 +52,21 @@
      * @param {number} index The index of the element to get.
      * @return {*} The element at the given index.
      */
-    item: function(index) {
+    item(index) {
       if (index >= 0 && index < this.length) {
         return this.array_[this.indexes_[index]];
       }
       return undefined;
-    },
+    }
 
     /**
      * Returns compare function set for given field.
      * @param {string} field The field to get compare function for.
      * @return {function(*, *): number} Compare function set for given field.
      */
-    compareFunction: function(field) {
+    compareFunction(field) {
       return this.compareFunctions_[field];
-    },
+    }
 
     /**
      * Sets compare function for given field.
@@ -74,21 +74,21 @@
      * @param {function(*, *): number} compareFunction Compare function to set
      *     for given field.
      */
-    setCompareFunction: function(field, compareFunction) {
+    setCompareFunction(field, compareFunction) {
       if (!this.compareFunctions_) {
         this.compareFunctions_ = {};
       }
       this.compareFunctions_[field] = compareFunction;
-    },
+    }
 
     /**
      * Returns true if the field has a compare function.
      * @param {string} field The field to check.
      * @return {boolean} True if the field is sortable.
      */
-    isSortable: function(field) {
+    isSortable(field) {
       return this.compareFunctions_ && field in this.compareFunctions_;
-    },
+    }
 
     /**
      * Returns current sort status.
@@ -101,7 +101,7 @@
       } else {
         return this.createSortStatus(null, null);
       }
-    },
+    }
 
     /**
      * Returns the first matching item.
@@ -110,14 +110,14 @@
      *     the {@code opt_fromIndex}.
      * @return {number} The index of the first found element or -1 if not found.
      */
-    indexOf: function(item, opt_fromIndex) {
+    indexOf(item, opt_fromIndex) {
       for (let i = opt_fromIndex || 0; i < this.indexes_.length; i++) {
         if (item === this.item(i)) {
           return i;
         }
       }
       return -1;
-    },
+    }
 
     /**
      * Returns an array of elements in a selected range.
@@ -125,12 +125,12 @@
      * @param {number=} opt_to The ending index of selected range.
      * @return {Array} An array of elements in the selected range.
      */
-    slice: function(opt_from, opt_to) {
+    slice(opt_from, opt_to) {
       const arr = this.array_;
       return this.indexes_.slice(opt_from, opt_to).map(function(index) {
         return arr[index];
       });
-    },
+    }
 
     /**
      * This removes and adds items to the model.
@@ -142,7 +142,7 @@
      * @param {...*} var_args The items to add.
      * @return {!Array} An array with the removed items.
      */
-    splice: function(index, deleteCount, var_args) {
+    splice(index, deleteCount, var_args) {
       const addCount = arguments.length - 2;
       const newIndexes = [];
       const deletePermutation = [];
@@ -209,7 +209,7 @@
       }
 
       return deletedItems;
-    },
+    }
 
     /**
      * Appends items to the end of the model.
@@ -219,12 +219,12 @@
      * @param {...*} var_args The items to append.
      * @return {number} The new length of the model.
      */
-    push: function(var_args) {
+    push(var_args) {
       const args = Array.prototype.slice.call(arguments);
       args.unshift(this.length, 0);
       this.splice.apply(this, args);
       return this.length;
-    },
+    }
 
     /**
      * Updates the existing item with the new item.
@@ -236,14 +236,14 @@
      *     is not found in the model, the method call is just ignored.
      * @param {*} newItem New item.
      */
-    replaceItem: function(oldItem, newItem) {
+    replaceItem(oldItem, newItem) {
       const index = this.indexOf(oldItem);
       if (index < 0) {
         return;
       }
       this.array_[this.indexes_[index]] = newItem;
       this.updateIndex(index);
-    },
+    }
 
     /**
      * Use this to update a given item in the array. This does not remove and
@@ -252,9 +252,9 @@
      * This runs sort after updating.
      * @param {number} index The index of the item to update.
      */
-    updateIndex: function(index) {
+    updateIndex(index) {
       this.updateIndexes([index]);
-    },
+    }
 
     /**
      * Notifies of update of the items in the array. This does not remove and
@@ -263,7 +263,7 @@
      * This runs sort after updating.
      * @param {Array<number>} indexes The index list of items to update.
      */
-    updateIndexes: function(indexes) {
+    updateIndexes(indexes) {
       indexes.forEach(function(index) {
         assert(index >= 0 && index < this.length, 'Invalid index');
       }, this);
@@ -286,7 +286,7 @@
         // list will not go to inconsistent state.
         this.delayedSort_(status.field, status.direction);
       }
-    },
+    }
 
     /**
      * Creates sort status with given field and direction.
@@ -294,9 +294,9 @@
      * @param {?string} direction Sort direction.
      * @return {!Object} Created sort status.
      */
-    createSortStatus: function(field, direction) {
+    createSortStatus(field, direction) {
       return {field: field, direction: direction};
-    },
+    }
 
     /**
      * Called before a sort happens so that you may fetch additional data
@@ -306,9 +306,9 @@
      * @param {function()} callback The function to invoke when preparation
      *     is complete.
      */
-    prepareSort: function(field, callback) {
+    prepareSort(field, callback) {
       callback();
-    },
+    }
 
     /**
      * Sorts data model according to given field and direction and dispathes
@@ -317,7 +317,7 @@
      * @param {string} direction Sort direction.
      * @private
      */
-    delayedSort_: function(field, direction) {
+    delayedSort_(field, direction) {
       const self = this;
       setTimeout(function() {
         // If the sort status has been changed, sorting has already done
@@ -327,7 +327,7 @@
           self.sort(field, direction);
         }
       }, 0);
-    },
+    }
 
     /**
      * Sorts data model according to given field and direction and dispathes
@@ -335,7 +335,7 @@
      * @param {string} field Sort field.
      * @param {string} direction Sort direction.
      */
-    sort: function(field, direction) {
+    sort(field, direction) {
       const self = this;
 
       this.prepareSort(field, function() {
@@ -345,7 +345,7 @@
         }
         self.dispatchSortEvent_();
       });
-    },
+    }
 
     /**
      * Sorts data model according to given field and direction.
@@ -353,7 +353,7 @@
      * @param {string} direction Sort direction.
      * @private
      */
-    doSort_: function(field, direction) {
+    doSort_(field, direction) {
       const compareFunction = this.sortFunction_(field, direction);
       const positions = [];
       for (let i = 0; i < this.length; i++) {
@@ -378,19 +378,19 @@
         return sortPermutation;
       }
       return null;
-    },
+    }
 
-    dispatchSortEvent_: function() {
+    dispatchSortEvent_() {
       const e = new Event('sorted');
       this.dispatchEvent(e);
-    },
+    }
 
-    dispatchPermutedEvent_: function(permutation) {
+    dispatchPermutedEvent_(permutation) {
       const e = new Event('permuted');
       e.permutation = permutation;
       e.newLength = this.length;
       this.dispatchEvent(e);
-    },
+    }
 
     /**
      * Creates compare function for the field.
@@ -400,7 +400,7 @@
      * @return {function(*, *): number} Compare function.
      * @private
      */
-    createCompareFunction_: function(field) {
+    createCompareFunction_(field) {
       const compareFunction =
           this.compareFunctions_ ? this.compareFunctions_[field] : null;
       const defaultValuesCompareFunction = this.defaultValuesCompareFunction;
@@ -411,7 +411,7 @@
           return defaultValuesCompareFunction.call(null, a[field], b[field]);
         };
       }
-    },
+    }
 
     /**
      * Creates compare function for given field and direction.
@@ -419,7 +419,7 @@
      * @param {string} direction Sort direction.
      * @private
      */
-    sortFunction_: function(field, direction) {
+    sortFunction_(field, direction) {
       let compareFunction = null;
       if (field !== null) {
         compareFunction = this.createCompareFunction_(field);
@@ -440,12 +440,12 @@
         return dirMultiplier *
             this.defaultValuesCompareFunction(index1, index2);
       }.bind(this);
-    },
+    }
 
     /**
      * Default compare function.
      */
-    defaultValuesCompareFunction: function(a, b) {
+    defaultValuesCompareFunction(a, b) {
       // We could insert i18n comparisons here.
       if (a < b) {
         return -1;
@@ -455,7 +455,7 @@
       }
       return 0;
     }
-  };
+  }
 
   return {ArrayDataModel: ArrayDataModel};
 });
diff --git a/ui/webui/resources/js/cr/ui/context_menu_handler.js b/ui/webui/resources/js/cr/ui/context_menu_handler.js
index 9ae205b..e2a348bc 100644
--- a/ui/webui/resources/js/cr/ui/context_menu_handler.js
+++ b/ui/webui/resources/js/cr/ui/context_menu_handler.js
@@ -5,31 +5,34 @@
 // require: event_target.js
 
 cr.define('cr.ui', function() {
-  /** @const */ const EventTarget = cr.EventTarget;
   /** @const */ const Menu = cr.ui.Menu;
 
   /**
    * Handles context menus.
-   * @constructor
-   * @extends {cr.EventTarget}
    * @implements {EventListener}
    */
-  function ContextMenuHandler() {
-    /** @private {!EventTracker} */
-    this.showingEvents_ = new EventTracker();
-  }
+  class ContextMenuHandler extends cr.EventTarget {
+    constructor() {
+      super();
+      /** @private {!EventTracker} */
+      this.showingEvents_ = new EventTracker();
 
-  ContextMenuHandler.prototype = {
-    __proto__: EventTarget.prototype,
+      /**
+       * The menu that we are currently showing.
+       * @private {?cr.ui.Menu}
+       */
+      this.menu_ = null;
 
-    /**
-     * The menu that we are currently showing.
-     * @type {cr.ui.Menu}
-     */
-    menu_: null,
+      /** @private {?number} */
+      this.hideTimestamp_ = null;
+
+      /** @private {boolean} */
+      this.keyIsDown_ = false;
+    }
+
     get menu() {
       return this.menu_;
-    },
+    }
 
     /**
      * Shows a menu as a context menu.
@@ -37,7 +40,7 @@
      *     event).
      * @param {!cr.ui.Menu} menu The menu to show.
      */
-    showMenu: function(e, menu) {
+    showMenu(e, menu) {
       menu.updateCommands(assertInstanceof(e.currentTarget, Node));
       if (!menu.hasVisibleItems()) {
         return;
@@ -66,14 +69,14 @@
       ev.element = menu.contextElement;
       ev.menu = menu;
       this.dispatchEvent(ev);
-    },
+    }
 
     /**
      * Hide the currently shown menu.
      * @param {cr.ui.HideType=} opt_hideType Type of hide.
      *     default: cr.ui.HideType.INSTANT.
      */
-    hideMenu: function(opt_hideType) {
+    hideMenu(opt_hideType) {
       const menu = this.menu;
       if (!menu) {
         return;
@@ -100,7 +103,7 @@
       ev.element = originalContextElement;
       ev.menu = menu;
       this.dispatchEvent(ev);
-    },
+    }
 
     /**
      * Positions the menu
@@ -108,7 +111,7 @@
      * @param {!cr.ui.Menu} menu The menu to position.
      * @private
      */
-    positionMenu_: function(e, menu) {
+    positionMenu_(e, menu) {
       // TODO(arv): Handle scrolled documents when needed.
 
       const element = e.currentTarget;
@@ -128,13 +131,13 @@
       }
 
       cr.ui.positionPopupAtPoint(x, y, menu);
-    },
+    }
 
     /**
      * Handles event callbacks.
      * @param {!Event} e The event object.
      */
-    handleEvent: function(e) {
+    handleEvent(e) {
       // Keep track of keydown state so that we can use that to determine the
       // reason for the contextmenu event.
       switch (e.type) {
@@ -221,14 +224,14 @@
           e.stopPropagation();
           break;
       }
-    },
+    }
 
     /**
      * Adds a contextMenu property to an element or element class.
      * @param {!Element|!Function} elementOrClass The element or class to add
      *     the contextMenu property to.
      */
-    addContextMenuProperty: function(elementOrClass) {
+    addContextMenuProperty(elementOrClass) {
       const target = typeof elementOrClass == 'function' ?
           elementOrClass.prototype :
           elementOrClass;
@@ -277,7 +280,7 @@
           return this.getBoundingClientRect();
         };
       }
-    },
+    }
 
     /**
      * Sets the given contextMenu to the given element. A contextMenu property
@@ -285,13 +288,13 @@
      * @param {!Element} element The element or class to set the contextMenu to.
      * @param {!cr.ui.Menu} contextMenu The contextMenu property to be set.
      */
-    setContextMenu: function(element, contextMenu) {
+    setContextMenu(element, contextMenu) {
       if (!element.contextMenu) {
         this.addContextMenuProperty(element);
       }
       element.contextMenu = contextMenu;
     }
-  };
+  }
 
   /**
    * The singleton context menu handler.
diff --git a/ui/webui/resources/js/cr/ui/list_selection_model.js b/ui/webui/resources/js/cr/ui/list_selection_model.js
index 7046cfb..0bd052db 100644
--- a/ui/webui/resources/js/cr/ui/list_selection_model.js
+++ b/ui/webui/resources/js/cr/ui/list_selection_model.js
@@ -3,28 +3,35 @@
 // found in the LICENSE file.
 
 cr.define('cr.ui', function() {
-  /** @const */ const EventTarget = cr.EventTarget;
-
   /**
    * Creates a new selection model that is to be used with lists.
    *
-   * @param {number=} opt_length The number items in the selection.
-   *
-   * @constructor
-   * @extends {cr.EventTarget}
    */
-  function ListSelectionModel(opt_length) {
-    this.length_ = opt_length || 0;
-    // Even though selectedIndexes_ is really a map we use an array here to get
-    // iteration in the order of the indexes.
-    this.selectedIndexes_ = [];
+  class ListSelectionModel extends cr.EventTarget {
+    /**
+     * @param {number=} opt_length The number items in the selection.
+     */
+    constructor(opt_length) {
+      super();
+      this.length_ = opt_length || 0;
+      // Even though selectedIndexes_ is really a map we use an array here to
+      // get iteration in the order of the indexes.
+      this.selectedIndexes_ = [];
 
-    // True if any item could be lead or anchor. False if only selected ones.
-    this.independentLeadItem_ = !cr.isMac && !cr.isChromeOS;
-  }
+      // True if any item could be lead or anchor. False if only selected ones.
+      this.independentLeadItem_ = !cr.isMac && !cr.isChromeOS;
 
-  ListSelectionModel.prototype = {
-    __proto__: EventTarget.prototype,
+      this.leadIndex_ = -1;
+      this.oldLeadIndex_ = null;
+      this.anchorIndex_ = -1;
+      this.oldAnchorIndex_ = null;
+
+      /** @private {?number} */
+      this.changeCount_;
+
+      /** @private {?Object} */
+      this.changedIndexes_;
+    }
 
     /**
      * The number of items in the model.
@@ -32,7 +39,7 @@
      */
     get length() {
       return this.length_;
-    },
+    }
 
     /**
      * The selected indexes.
@@ -41,7 +48,8 @@
      */
     get selectedIndexes() {
       return Object.keys(this.selectedIndexes_).map(Number);
-    },
+    }
+
     set selectedIndexes(selectedIndexes) {
       this.beginChange();
       const unselected = {};
@@ -83,7 +91,7 @@
         this.leadIndex = this.anchorIndex = -1;
       }
       this.endChange();
-    },
+    }
 
     /**
      * Convenience getter which returns the first selected index.
@@ -95,10 +103,11 @@
         return Number(i);
       }
       return -1;
-    },
+    }
+
     set selectedIndex(selectedIndex) {
       this.selectedIndexes = selectedIndex != -1 ? [selectedIndex] : [];
-    },
+    }
 
     /**
      * Returns the nearest selected index or -1 if no item selected.
@@ -106,7 +115,7 @@
      * @return {number}
      * @private
      */
-    getNearestSelectedIndex_: function(index) {
+    getNearestSelectedIndex_(index) {
       if (index == -1) {
         // If no index is provided, pick the first selected index if there is
         // one.
@@ -123,7 +132,7 @@
         }
       }
       return result < this.length ? Number(result) : -1;
-    },
+    }
 
     /**
      * Selects a range of indexes, starting with {@code start} and ends with
@@ -131,7 +140,7 @@
      * @param {number} start The first index to select.
      * @param {number} end The last index to select.
      */
-    selectRange: function(start, end) {
+    selectRange(start, end) {
       // Swap if starts comes after end.
       if (start > end) {
         const tmp = start;
@@ -147,47 +156,47 @@
       this.setIndexSelected(end, true);
 
       this.endChange();
-    },
+    }
 
     /**
      * Selects all indexes.
      */
-    selectAll: function() {
+    selectAll() {
       if (this.length === 0) {
         return;
       }
 
       this.selectRange(0, this.length - 1);
-    },
+    }
 
     /**
      * Clears the selection
      */
-    clear: function() {
+    clear() {
       this.beginChange();
       this.length_ = 0;
       this.anchorIndex = this.leadIndex = -1;
       this.unselectAll();
       this.endChange();
-    },
+    }
 
     /**
      * Unselects all selected items.
      */
-    unselectAll: function() {
+    unselectAll() {
       this.beginChange();
       for (const i in this.selectedIndexes_) {
         this.setIndexSelected(+i, false);
       }
       this.endChange();
-    },
+    }
 
     /**
      * Sets the selected state for an index.
      * @param {number} index The index to set the selected state for.
      * @param {boolean} b Whether to select the index or not.
      */
-    setIndexSelected: function(index, b) {
+    setIndexSelected(index, b) {
       const oldSelected = index in this.selectedIndexes_;
       if (oldSelected == b) {
         return;
@@ -205,22 +214,22 @@
 
       // End change dispatches an event which in turn may update the view.
       this.endChange();
-    },
+    }
 
     /**
      * Whether a given index is selected or not.
      * @param {number} index The index to check.
      * @return {boolean} Whether an index is selected.
      */
-    getIndexSelected: function(index) {
+    getIndexSelected(index) {
       return index in this.selectedIndexes_;
-    },
+    }
 
     /**
      * This is used to begin batching changes. Call {@code endChange} when you
      * are done making changes.
      */
-    beginChange: function() {
+    beginChange() {
       if (!this.changeCount_) {
         this.changeCount_ = 0;
         this.changedIndexes_ = {};
@@ -228,13 +237,13 @@
         this.oldAnchorIndex_ = this.anchorIndex_;
       }
       this.changeCount_++;
-    },
+    }
 
     /**
      * Call this after changes are done and it will dispatch a change event if
      * any changes were actually done.
      */
-    endChange: function() {
+    endChange() {
       this.changeCount_--;
       if (!this.changeCount_) {
         // Calls delayed |dispatchPropertyChange|s, only when |leadIndex| or
@@ -253,7 +262,8 @@
         }
         this.oldAnchorIndex_ = null;
 
-        const indexes = Object.keys(this.changedIndexes_);
+        const indexes = Object.keys(
+            /** @type {!Object} */ (this.changedIndexes_));
         if (indexes.length) {
           const e = new Event('change');
           e.changes = indexes.map(function(index) {
@@ -266,10 +276,7 @@
         }
         this.changedIndexes_ = {};
       }
-    },
-
-    leadIndex_: -1,
-    oldLeadIndex_: null,
+    }
 
     /**
      * The leadIndex is used with multiple selection and it is the index that
@@ -278,7 +285,8 @@
      */
     get leadIndex() {
       return this.leadIndex_;
-    },
+    }
+
     set leadIndex(leadIndex) {
       const oldValue = this.leadIndex_;
       const newValue = this.adjustIndex_(leadIndex);
@@ -287,10 +295,7 @@
       if (!this.changeCount_ && newValue != oldValue) {
         cr.dispatchPropertyChange(this, 'leadIndex', newValue, oldValue);
       }
-    },
-
-    anchorIndex_: -1,
-    oldAnchorIndex_: null,
+    }
 
     /**
      * The anchorIndex is used with multiple selection.
@@ -298,7 +303,8 @@
      */
     get anchorIndex() {
       return this.anchorIndex_;
-    },
+    }
+
     set anchorIndex(anchorIndex) {
       const oldValue = this.anchorIndex_;
       const newValue = this.adjustIndex_(anchorIndex);
@@ -307,7 +313,7 @@
       if (!this.changeCount_ && newValue != oldValue) {
         cr.dispatchPropertyChange(this, 'anchorIndex', newValue, oldValue);
       }
-    },
+    }
 
     /**
      * Helper method that adjustes a value before assiging it to leadIndex or
@@ -315,7 +321,7 @@
      * @param {number} index New value for leadIndex or anchorIndex.
      * @return {number} Corrected value.
      */
-    adjustIndex_: function(index) {
+    adjustIndex_(index) {
       index = Math.max(-1, Math.min(this.length_ - 1, index));
       // On Mac and ChromeOS lead and anchor items are forced to be among
       // selected items. This rule is not enforces until end of batch update.
@@ -325,7 +331,7 @@
         index = index2;
       }
       return index;
-    },
+    }
 
     /**
      * Whether the selection model supports multiple selected items.
@@ -333,13 +339,13 @@
      */
     get multiple() {
       return true;
-    },
+    }
 
     /**
      * Adjusts the selection after reordering of items in the table.
      * @param {!Array<number>} permutation The reordering permutation.
      */
-    adjustToReordering: function(permutation) {
+    adjustToReordering(permutation) {
       this.beginChange();
       const oldLeadIndex = this.leadIndex;
       const oldAnchorIndex = this.anchorIndex;
@@ -376,16 +382,16 @@
       }
 
       this.endChange();
-    },
+    }
 
     /**
      * Adjusts selection model length.
      * @param {number} length New selection model length.
      */
-    adjustLength: function(length) {
+    adjustLength(length) {
       this.length_ = length;
     }
-  };
+  }
 
   return {ListSelectionModel: ListSelectionModel};
 });
diff --git a/ui/webui/resources/js/cr/ui/list_single_selection_model.js b/ui/webui/resources/js/cr/ui/list_single_selection_model.js
index 859247e..50af5df 100644
--- a/ui/webui/resources/js/cr/ui/list_single_selection_model.js
+++ b/ui/webui/resources/js/cr/ui/list_single_selection_model.js
@@ -3,27 +3,34 @@
 // found in the LICENSE file.
 
 cr.define('cr.ui', function() {
-  /** @const */ const EventTarget = cr.EventTarget;
-
   /**
    * Creates a new selection model that is to be used with lists. This only
    * allows a single index to be selected.
-   *
-   * @param {number=} opt_length The number items in the selection.
-   *
-   * @constructor
-   * @extends {cr.EventTarget}
    */
-  function ListSingleSelectionModel(opt_length) {
-    this.length_ = opt_length || 0;
-    this.selectedIndex = -1;
+  class ListSingleSelectionModel extends cr.EventTarget {
+    /**
+     * @param {number=} opt_length The number items in the selection.
+     */
+    constructor(opt_length) {
+      super();
+      this.length_ = opt_length || 0;
+      this.selectedIndex = -1;
 
-    // True if any item could be lead or anchor. False if only selected ones.
-    this.independentLeadItem_ = !cr.isMac && !cr.isChromeOS;
-  }
+      // True if any item could be lead or anchor. False if only selected ones.
+      this.independentLeadItem_ = !cr.isMac && !cr.isChromeOS;
 
-  ListSingleSelectionModel.prototype = {
-    __proto__: EventTarget.prototype,
+      /** @private {number} */
+      this.leadIndex_ = -1;
+
+      /** @private {?number} */
+      this.selectedIndex_;
+
+      /** @private {?number} */
+      this.selectedIndexBefore_;
+
+      /** @private {?number} */
+      this.changeCount_;
+    }
 
     /**
      * The number of items in the model.
@@ -31,7 +38,7 @@
      */
     get length() {
       return this.length_;
-    },
+    }
 
     /**
      * @type {!Array} The selected indexes.
@@ -39,10 +46,11 @@
     get selectedIndexes() {
       const i = this.selectedIndex;
       return i != -1 ? [this.selectedIndex] : [];
-    },
+    }
+
     set selectedIndexes(indexes) {
       this.selectedIndex = indexes.length ? indexes[0] : -1;
-    },
+    }
 
     /**
      * Convenience getter which returns the first selected index.
@@ -51,7 +59,8 @@
      */
     get selectedIndex() {
       return this.selectedIndex_;
-    },
+    }
+
     set selectedIndex(selectedIndex) {
       const oldSelectedIndex = this.selectedIndex;
       const i = Math.max(-1, Math.min(this.length_ - 1, selectedIndex));
@@ -62,7 +71,7 @@
         this.leadIndex = i >= 0 ? i : this.leadIndex;
         this.endChange();
       }
-    },
+    }
 
     /**
      * Selects a range of indexes, starting with {@code start} and ends with
@@ -70,41 +79,41 @@
      * @param {number} start The first index to select.
      * @param {number} end The last index to select.
      */
-    selectRange: function(start, end) {
+    selectRange(start, end) {
       // Only select first index.
       this.selectedIndex = Math.min(start, end);
-    },
+    }
 
     /**
      * Selects all indexes.
      */
-    selectAll: function() {
+    selectAll() {
       // Select all is not allowed on a single selection model
-    },
+    }
 
     /**
      * Clears the selection
      */
-    clear: function() {
+    clear() {
       this.beginChange();
       this.length_ = 0;
       this.selectedIndex = this.anchorIndex = this.leadIndex = -1;
       this.endChange();
-    },
+    }
 
     /**
      * Unselects all selected items.
      */
-    unselectAll: function() {
+    unselectAll() {
       this.selectedIndex = -1;
-    },
+    }
 
     /**
      * Sets the selected state for an index.
      * @param {number} index The index to set the selected state for.
      * @param {boolean} b Whether to select the index or not.
      */
-    setIndexSelected: function(index, b) {
+    setIndexSelected(index, b) {
       // Only allow selection
       const oldSelected = index == this.selectedIndex_;
       if (oldSelected == b) {
@@ -116,34 +125,34 @@
       } else if (index == this.selectedIndex_) {
         this.selectedIndex = -1;
       }
-    },
+    }
 
     /**
      * Whether a given index is selected or not.
      * @param {number} index The index to check.
      * @return {boolean} Whether an index is selected.
      */
-    getIndexSelected: function(index) {
+    getIndexSelected(index) {
       return index == this.selectedIndex_;
-    },
+    }
 
     /**
      * This is used to begin batching changes. Call {@code endChange} when you
      * are done making changes.
      */
-    beginChange: function() {
+    beginChange() {
       if (!this.changeCount_) {
         this.changeCount_ = 0;
         this.selectedIndexBefore_ = this.selectedIndex_;
       }
       this.changeCount_++;
-    },
+    }
 
     /**
      * Call this after changes are done and it will dispatch a change event if
      * any changes were actually done.
      */
-    endChange: function() {
+    endChange() {
       this.changeCount_--;
       if (!this.changeCount_) {
         if (this.selectedIndexBefore_ != this.selectedIndex_) {
@@ -155,13 +164,13 @@
           }
         }
       }
-    },
+    }
 
     /**
      * Creates event with specified name and fills its {changes} property.
      * @param {string} eventName Event name.
      */
-    createChangeEvent: function(eventName) {
+    createChangeEvent(eventName) {
       const e = new Event(eventName);
       const indexes = [this.selectedIndexBefore_, this.selectedIndex_];
       e.changes =
@@ -174,9 +183,7 @@
               }, this);
 
       return e;
-    },
-
-    leadIndex_: -1,
+    }
 
     /**
      * The leadIndex is used with multiple selection and it is the index that
@@ -185,7 +192,8 @@
      */
     get leadIndex() {
       return this.leadIndex_;
-    },
+    }
+
     set leadIndex(leadIndex) {
       const li = this.adjustIndex_(leadIndex);
       if (li != this.leadIndex_) {
@@ -194,15 +202,15 @@
         cr.dispatchPropertyChange(this, 'leadIndex', li, oldLeadIndex);
         cr.dispatchPropertyChange(this, 'anchorIndex', li, oldLeadIndex);
       }
-    },
+    }
 
-    adjustIndex_: function(index) {
+    adjustIndex_(index) {
       index = Math.max(-1, Math.min(this.length_ - 1, index));
       if (!this.independentLeadItem_) {
         index = this.selectedIndex;
       }
       return index;
-    },
+    }
 
     /**
      * The anchorIndex is used with multiple selection.
@@ -210,10 +218,11 @@
      */
     get anchorIndex() {
       return this.leadIndex;
-    },
+    }
+
     set anchorIndex(anchorIndex) {
       this.leadIndex = anchorIndex;
-    },
+    }
 
     /**
      * Whether the selection model supports multiple selected items.
@@ -221,13 +230,13 @@
      */
     get multiple() {
       return false;
-    },
+    }
 
     /**
      * Adjusts the selection after reordering of items in the table.
      * @param {!Array<number>} permutation The reordering permutation.
      */
-    adjustToReordering: function(permutation) {
+    adjustToReordering(permutation) {
       if (this.leadIndex != -1) {
         this.leadIndex = permutation[this.leadIndex];
       }
@@ -236,16 +245,16 @@
       if (oldSelectedIndex != -1) {
         this.selectedIndex = permutation[oldSelectedIndex];
       }
-    },
+    }
 
     /**
      * Adjusts selection model length.
      * @param {number} length New selection model length.
      */
-    adjustLength: function(length) {
+    adjustLength(length) {
       this.length_ = length;
     }
-  };
+  }
 
   return {ListSingleSelectionModel: ListSingleSelectionModel};
 });
diff --git a/ui/webui/resources/js/cr/ui/page_manager/page.js b/ui/webui/resources/js/cr/ui/page_manager/page.js
index c0b72d3..6c40a9ea 100644
--- a/ui/webui/resources/js/cr/ui/page_manager/page.js
+++ b/ui/webui/resources/js/cr/ui/page_manager/page.js
@@ -13,92 +13,102 @@
    * point, one root Page is visible, and any visible Page can show a child Page
    * as an overlay. The host of the root Page(s) should provide a container div
    * for each nested level to enforce the stack order of overlays.
-   * @constructor
-   * @param {string} name Page name.
-   * @param {string} title Page title, used for history.
-   * @param {string} pageDivName ID of the div corresponding to the page.
-   * @extends {cr.EventTarget}
    */
-  function Page(name, title, pageDivName) {
-    this.name = name;
-    this.title = title;
-    this.pageDivName = pageDivName;
-    this.pageDiv = getRequiredElement(this.pageDivName);
-    // |pageDiv.page| is set to the page object (this) when the page is visible
-    // to track which page is being shown when multiple pages can share the same
-    // underlying div.
-    this.pageDiv.page = null;
-    this.tab = null;
-    this.lastFocusedElement = null;
-    this.hash = '';
-  }
-
-  Page.prototype = {
-    __proto__: cr.EventTarget.prototype,
-
+  class Page extends cr.EventTarget {
     /**
-     * The parent page of this page, or null for root pages.
-     * @type {cr.ui.pageManager.Page}
+     * @param {string} name Page name.
+     * @param {string} title Page title, used for history.
+     * @param {string} pageDivName ID of the div corresponding to the page.
      */
-    parentPage: null,
+    constructor(name, title, pageDivName) {
+      super();
 
-    /**
-     * The section on the parent page that is associated with this page.
-     * Can be null.
-     * @type {Element}
-     */
-    associatedSection: null,
+      this.name = name;
+      this.title = title;
+      this.pageDivName = pageDivName;
+      this.pageDiv = getRequiredElement(this.pageDivName);
+      // |pageDiv.page| is set to the page object (this) when the page is
+      // visible to track which page is being shown when multiple pages can
+      // share the same underlying div.
+      this.pageDiv.page = null;
+      this.tab = null;
+      this.lastFocusedElement = null;
+      this.hash = '';
 
-    /**
-     * An array of controls that are associated with this page. The first
-     * control should be located on a root page.
-     * @type {Array<Element>}
-     */
-    associatedControls: null,
+      /**
+       * The parent page of this page; or null for root pages.
+       * @type {cr.ui.pageManager.Page}
+       */
+      this.parentPage = null;
 
-    /**
-     * If true, this page should always be considered the top-most page when
-     * visible.
-     * @type {boolean}
-     */
-    alwaysOnTop_: false,
+      /**
+       * The section on the parent page that is associated with this page.
+       * Can be null.
+       * @type {Element}
+       */
+      this.associatedSection = null;
+
+      /**
+       * An array of controls that are associated with this page. The first
+       * control should be located on a root page.
+       * @type {Array<Element>}
+       */
+      this.associatedControls = null;
+
+      /**
+       * If true; this page should always be considered the top-most page when
+       * visible.
+       * @private {boolean}
+       */
+      this.alwaysOnTop_ = false;
+
+      /**
+       * Set this to handle cancelling an overlay (and skip some typical steps).
+       * @see {cr.ui.PageManager.prototype.cancelOverlay}
+       * @type {?Function}
+       */
+      this.handleCancel = null;
+
+      /** @type {boolean} */
+      this.isOverlay = false;
+    }
 
     /**
      * Initializes page content.
      */
-    initializePage: function() {},
+    initializePage() {}
 
     /**
      * Called by the PageManager when this.hash changes while the page is
      * already visible. This is analogous to the hashchange DOM event.
      */
-    didChangeHash: function() {},
+    didChangeHash() {}
 
     /**
      * Sets focus on the first focusable element. Override for a custom focus
      * strategy.
      */
-    focus: function() {
+    focus() {
       cr.ui.setInitialFocus(this.pageDiv);
-    },
+    }
 
     /**
      * Reverse any buttons strips in this page (only applies to overlays).
      * @see cr.ui.reverseButtonStrips for an explanation of why this is
      * necessary and when it's done.
      */
-    reverseButtonStrip: function() {
+    reverseButtonStrip() {
       assert(this.isOverlay);
       cr.ui.reverseButtonStrips(this.pageDiv);
-    },
+    }
 
     /**
      * Whether it should be possible to show the page.
      * @return {boolean} True if the page should be shown.
      */
-    canShowPage: function() {
+    canShowPage() {
       return true;
-    },
+    }
 
     /**
      * Updates the hash of the current page. If the page is topmost, the history
@@ -106,36 +116,29 @@
      * @param {string} hash The new hash value. Like location.hash, this
      *     should include the leading '#' if not empty.
      */
-    setHash: function(hash) {
+    setHash(hash) {
       if (this.hash == hash) {
         return;
       }
       this.hash = hash;
       PageManager.onPageHashChanged(this);
-    },
+    }
 
     /**
      * Called after the page has been shown.
      */
-    didShowPage: function() {},
-
-    /**
-     * Set this to handle cancelling an overlay (and skip some typical steps).
-     * @see {cr.ui.PageManager.prototype.cancelOverlay}
-     * @type {?Function}
-     */
-    handleCancel: null,
+    didShowPage() {}
 
     /**
      * Called before the page will be hidden, e.g., when a different root page
      * will be shown.
      */
-    willHidePage: function() {},
+    willHidePage() {}
 
     /**
      * Called after the overlay has been closed.
      */
-    didClosePage: function() {},
+    didClosePage() {}
 
     /**
      * Gets the container div for this page if it is an overlay.
@@ -144,7 +147,7 @@
     get container() {
       assert(this.isOverlay);
       return this.pageDiv.parentNode;
-    },
+    }
 
     /**
      * Gets page visibility state.
@@ -160,7 +163,7 @@
         return false;
       }
       return this.pageDiv.page == this;
-    },
+    }
 
     /**
      * Sets page visibility.
@@ -183,7 +186,7 @@
       }
 
       cr.dispatchPropertyChange(this, 'visible', visible, !visible);
-    },
+    }
 
     /**
      * Whether the page is considered 'sticky', such that it will remain a root
@@ -192,7 +195,7 @@
      */
     get sticky() {
       return false;
-    },
+    }
 
     /**
      * @type {boolean} True if this page should always be considered the
@@ -200,7 +203,7 @@
      */
     get alwaysOnTop() {
       return this.alwaysOnTop_;
-    },
+    }
 
     /**
      * @type {boolean} True if this page should always be considered the
@@ -209,14 +212,14 @@
     set alwaysOnTop(value) {
       assert(this.isOverlay);
       this.alwaysOnTop_ = value;
-    },
+    }
 
     /**
      * Shows or hides an overlay (including any visible dialog).
      * @param {boolean} visible Whether the overlay should be visible or not.
      * @private
      */
-    setOverlayVisible_: function(visible) {
+    setOverlayVisible_(visible) {
       assert(this.isOverlay);
       const pageDiv = this.pageDiv;
       const container = this.container;
@@ -286,13 +289,13 @@
       if (loading) {
         this.fadeCompleted_();
       }
-    },
+    }
 
     /**
      * Called when a container opacity transition finishes.
      * @private
      */
-    fadeCompleted_: function() {
+    fadeCompleted_() {
       if (this.container.classList.contains('transparent')) {
         this.pageDiv.hidden = true;
         this.container.hidden = true;
@@ -303,8 +306,8 @@
 
         PageManager.onPageVisibilityChanged(this);
       }
-    },
-  };
+    }
+  }
 
   // Export
   return {Page: Page};