diff --git a/AUTHORS b/AUTHORS
index 41cf3fc..e8e2daf 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -185,6 +185,7 @@
 Clement Scheelfeldt Skau <clementskau@gmail.com>
 Clinton Staley <clintstaley@gmail.com>
 Connor Pearson <cjp822@gmail.com>
+Conrad Irwin <conrad.irwin@gmail.com>
 Craig Schlenter <craig.schlenter@gmail.com>
 Csaba Osztrogonác <ossy.szeged@gmail.com>
 Daegyu Lee <na7jun8gi@gmail.com>
diff --git a/BUILD.gn b/BUILD.gn
index f52daa3c..a1249ed 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -706,7 +706,6 @@
       "//components/metrics:serialization",
       "//components/rappor:unit_tests",
       "//components/services/filesystem:filesystem_service_unittests",
-      "//components/services/leveldb:leveldb_service_unittests",
       "//components/sessions:unit_tests",
       "//media/blink:media_blink_unittests",
       "//media/cast:udp_proxy",
diff --git a/DEPS b/DEPS
index adcac60..adc7539 100644
--- a/DEPS
+++ b/DEPS
@@ -167,11 +167,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': 'e27a503a0a21af167e6a19d2e5c7b7e1039964bf',
+  'skia_revision': '0fc9b3829b476786f4a50a8e8e9469cd309c17ea',
   # 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': '0aff71c3ecaa48d359801e7f8864793f04aeee04',
+  'v8_revision': 'd0b81401bafdfcd2c96913e63faaa0ce6b382fa8',
   # 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.
@@ -179,7 +179,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': 'ef4c25e71c32487feade5e9f8e79cb569545b846',
+  'angle_revision': 'c5e0ac757a112a24a0118d434e652fd7b558e6a8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -230,7 +230,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': 'e74b5c944eda8877ae8d1058b427f61694b57f21',
+  'catapult_revision': 'df24b8a3609962fa2f491d52b8d68ece5a585715',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -298,11 +298,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': '621605ce2644d55ab74cb27a8afef97dc40f1b0f',
+  'shaderc_revision': '65adcb504d024bb29f0ad8279b6a215d5f679832',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'e09869ed526818cb01b4bdbe728ffe638ab5f861',
+  'dawn_revision': 'e16a901fb85351a93b224ea1b7b6d603a07fd1cc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -511,7 +511,7 @@
   },
 
   'src/ios/third_party/fishhook/src': {
-      'url': Var('chromium_git') + '/external/github.com/facebook/fishhook.git' + '@' + '80fe593736ac22162e77f891c7cba5095cf1cd4e',
+      'url': Var('chromium_git') + '/external/github.com/facebook/fishhook.git' + '@' + '66315a9c251edfe92f669ae2deeac0d75374c948',
       'condition': 'checkout_ios',
   },
 
@@ -862,7 +862,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'f86cc6ba6a29a05304901286bd461a0c6d59389b',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a441815f4dc37c2196a5b23182300bd0095f76ee',
       'condition': 'checkout_linux',
   },
 
@@ -887,7 +887,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'be83c310e3d5601c400d856a9963d1f413183d42',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3481902904a9e103f8391bc5e17385f537cadbab',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1146,7 +1146,7 @@
   },
 
   'src/third_party/libjpeg_turbo':
-    Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '38c693569427129fd8c22f4bba67685d7e176094',
+    Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '9d3bf3e9680156c48041c8b90fece504e3539a61',
 
   'src/third_party/liblouis/src': {
       'url': Var('chromium_git') + '/external/liblouis-github.git' + '@' + '67ab8e96cc2f4db70f220f71cbdee0903e8abac6',
@@ -1280,7 +1280,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '81425dcacf7414f7e5fdd66d2802256d0c61aedf',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'aa9175d6761d7ff7a172d637fda4a17df64453b5',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1467,10 +1467,10 @@
     Var('chromium_git') + '/external/github.com/SeleniumHQ/selenium/py.git' + '@' + 'd0045ec570c1a77612db35d1e92f05e1d27b4d53',
 
   'src/third_party/webgl/src':
-    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '7c4e67ff117d6c640e6dd17989afe2fb7da7eecb',
+    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '2701c130839edbeb226735b0775966b6423d9e83',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '955f8fd0477ea2d4137eff032184e02de8508043',
+    Var('webrtc_git') + '/src.git' + '@' + '066c2ab92f8034eea35ffced287ecaf08c9bb501',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1532,7 +1532,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b91063d99c88b47f7c603daa423f2a49910445bd',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@01cfdcb21734ff15dff696551b7cf4c6714e0959',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 2ba283ed..38a04803 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -544,7 +544,6 @@
     "java/src/org/chromium/android_webview/AwQuotaManagerBridge.java",
     "java/src/org/chromium/android_webview/AwRenderProcess.java",
     "java/src/org/chromium/android_webview/AwRenderProcessGoneDetail.java",
-    "java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java",
     "java/src/org/chromium/android_webview/AwScrollOffsetManager.java",
     "java/src/org/chromium/android_webview/AwServiceWorkerClient.java",
     "java/src/org/chromium/android_webview/AwServiceWorkerController.java",
diff --git a/android_webview/browser/aw_browser_context_unittest.cc b/android_webview/browser/aw_browser_context_unittest.cc
index a28ac0f..b8869d4 100644
--- a/android_webview/browser/aw_browser_context_unittest.cc
+++ b/android_webview/browser/aw_browser_context_unittest.cc
@@ -5,6 +5,7 @@
 #include "android_webview/browser/aw_browser_context.h"
 #include "android_webview/browser/aw_browser_process.h"
 #include "android_webview/browser/aw_feature_list_creator.h"
+#include "base/run_loop.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_content_client_initializer.h"
@@ -25,7 +26,15 @@
     browser_process_ = new AwBrowserProcess(aw_feature_list_creator);
   }
 
-  void TearDown() override { delete test_content_client_initializer_; }
+  void TearDown() override {
+    // Drain the message queue before destroying
+    // |test_content_client_initializer_|, otherwise a posted task may call
+    // content::GetNetworkConnectionTracker() after
+    // TestContentClientInitializer's destructor sets it to null.
+    base::RunLoop().RunUntilIdle();
+    delete test_content_client_initializer_;
+    delete browser_process_;
+  }
 
   // Create the TestBrowserThreads.
   content::BrowserTaskEnvironment task_environment_;
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java b/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java
deleted file mode 100644
index 10d260bc..0000000
--- a/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.android_webview;
-
-/**
- * Temporary adapter while downstream depends on this package name.
- */
-public class AwSafeBrowsingConfigHelper {
-    // Deprecated: remove this once downstream no longer depends on AwSafeBrowsingConfigHelper in
-    // this package name.
-    public static Boolean getSafeBrowsingUserOptIn() {
-        return org.chromium.android_webview.safe_browsing.AwSafeBrowsingConfigHelper
-                .getSafeBrowsingUserOptIn();
-    }
-
-    // Not meant to be instantiated.
-    private AwSafeBrowsingConfigHelper() {}
-}
diff --git a/ash/app_list/model/app_list_folder_item.h b/ash/app_list/model/app_list_folder_item.h
index 8a4863dec..4c140dc 100644
--- a/ash/app_list/model/app_list_folder_item.h
+++ b/ash/app_list/model/app_list_folder_item.h
@@ -112,7 +112,7 @@
 
   std::map<ash::AppListConfigType, std::unique_ptr<FolderImage>> folder_images_;
 
-  ScopedObserver<AppListConfigProvider, AppListFolderItem>
+  ScopedObserver<AppListConfigProvider, AppListConfigProvider::Observer>
       config_provider_observer_{this};
 
   DISALLOW_COPY_AND_ASSIGN(AppListFolderItem);
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc
index 557c227..4c79b268 100644
--- a/ash/app_list/views/app_list_folder_view.cc
+++ b/ash/app_list/views/app_list_folder_view.cc
@@ -721,10 +721,13 @@
   // Calculate bounds for page_switcher.
   gfx::Rect page_switcher_frame(rect);
   gfx::Size page_switcher_size = page_switcher_->GetPreferredSize();
-  page_switcher_size.set_height(GetAppListConfig().folder_header_height());
   page_switcher_frame.set_x(page_switcher_frame.right() -
                             page_switcher_size.width());
-  page_switcher_frame.set_y(header_frame.y());
+  // The page switcher has a different height than the folder header, but it
+  // still needs to be aligned with it.
+  page_switcher_frame.set_y(
+      header_frame.y() -
+      (page_switcher_size.height() - header_frame.height()) / 2);
   page_switcher_frame.set_size(page_switcher_size);
   view_model_->set_ideal_bounds(kIndexPageSwitcher, page_switcher_frame);
 }
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index a5e45f6..b1b73f09 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -1291,6 +1291,9 @@
       <message name="IDS_ASH_STATUS_TRAY_ETHERNET_ADDRESS" desc="The label for the mac address of the ethernet device.">
         Ethernet: <ph name="ADDRESS">$1<ex>01:23:45:67:89:AB</ex></ph>
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_CELLULAR_ADDRESS" desc="The label for the mac address of the cellular device.">
+        Cellular: <ph name="ADDRESS">$1<ex>01:23:45:67:89:AB</ex></ph>
+      </message>
       <message name="IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR" desc="Message for the status area when initializing the cellular device.">
         Initializing...
       </message>
diff --git a/ash/login/ui/lock_screen_media_controls_view.cc b/ash/login/ui/lock_screen_media_controls_view.cc
index 2af4842..539865b 100644
--- a/ash/login/ui/lock_screen_media_controls_view.cc
+++ b/ash/login/ui/lock_screen_media_controls_view.cc
@@ -530,10 +530,8 @@
   }
 
   // If |media_session_id_| resumed while waiting, don't hide the controls.
-  if (hide_controls_timer_->IsRunning() && request_id == media_session_id_) {
+  if (hide_controls_timer_->IsRunning() && request_id == media_session_id_)
     hide_controls_timer_->Stop();
-    enabled_actions_.clear();
-  }
 
   // If this session is different than the previous one, wait to see if the
   // previous one resumes before hiding the controls.
diff --git a/ash/login/ui/media_controls_header_view.cc b/ash/login/ui/media_controls_header_view.cc
index c647e04..846d8f5 100644
--- a/ash/login/ui/media_controls_header_view.cc
+++ b/ash/login/ui/media_controls_header_view.cc
@@ -27,12 +27,12 @@
 namespace {
 
 constexpr gfx::Insets kHeaderViewInsets = gfx::Insets(0, 0, 15, 0);
-constexpr int kIconSize = 18;
+constexpr int kIconViewSize = 18;
+constexpr int kIconSize = 12;
 constexpr int kHeaderTextFontSize = 12;
 constexpr gfx::Insets kIconPadding = gfx::Insets(1, 1, 1, 1);
 constexpr gfx::Insets kAppNamePadding = gfx::Insets(0, 10, 0, 0);
 constexpr gfx::Size kAppNamePreferredSize = gfx::Size(200, 10);
-constexpr int kIconCornerRadius = 1;
 constexpr gfx::Size kCloseButtonSize = gfx::Size(20, 20);
 constexpr int kCloseButtonIconSize = 18;
 constexpr gfx::Size kSpacerPreferredSize = gfx::Size(5, 5);
@@ -58,12 +58,12 @@
   layout->SetInteriorMargin(kHeaderViewInsets);
 
   auto app_icon_view = std::make_unique<views::ImageView>();
+  app_icon_view->SetPreferredSize(gfx::Size(kIconViewSize, kIconViewSize));
   app_icon_view->SetImageSize(gfx::Size(kIconSize, kIconSize));
-  app_icon_view->SetVerticalAlignment(views::ImageView::Alignment::kLeading);
-  app_icon_view->SetHorizontalAlignment(views::ImageView::Alignment::kLeading);
   app_icon_view->SetBorder(views::CreateEmptyBorder(kIconPadding));
   app_icon_view->SetBackground(
-      views::CreateRoundedRectBackground(SK_ColorWHITE, kIconCornerRadius));
+      views::CreateRoundedRectBackground(SK_ColorWHITE, kIconViewSize / 2));
+
   app_icon_view_ = AddChildView(std::move(app_icon_view));
 
   // Font list for text views.
diff --git a/ash/public/cpp/shelf_config.h b/ash/public/cpp/shelf_config.h
index 9907a76..e36bc86b4 100644
--- a/ash/public/cpp/shelf_config.h
+++ b/ash/public/cpp/shelf_config.h
@@ -58,7 +58,7 @@
 
   // OverviewObserver:
   void OnOverviewModeStartingAnimationComplete(bool canceled) override;
-  void OnOverviewModeEnded() override;
+  void OnOverviewModeEndingAnimationComplete(bool canceled) override;
 
   // Size of the shelf when visible (height when the shelf is horizontal and
   // width when the shelf is vertical).
diff --git a/ash/shelf/shelf_config.cc b/ash/shelf/shelf_config.cc
index ed81f20..6e0284b 100644
--- a/ash/shelf/shelf_config.cc
+++ b/ash/shelf/shelf_config.cc
@@ -126,7 +126,7 @@
   OnShelfConfigUpdated();
 }
 
-void ShelfConfig::OnOverviewModeEnded() {
+void ShelfConfig::OnOverviewModeEndingAnimationComplete(bool canceled) {
   OnShelfConfigUpdated();
 }
 
@@ -212,6 +212,7 @@
   if (!overview || !session)
     return false;
   return !overview->InOverviewSession() &&
+         !overview->IsCompletingShutdownAnimations() &&
          session->GetSessionState() == session_manager::SessionState::ACTIVE &&
          !is_app_list_visible_;
 }
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 2c45985..e2d490c 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -704,6 +704,21 @@
   MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE);
 }
 
+void ShelfLayoutManager::OnShelfItemSelected(ShelfAction action) {
+  switch (action) {
+    case SHELF_ACTION_NONE:
+    case SHELF_ACTION_APP_LIST_SHOWN:
+    case SHELF_ACTION_APP_LIST_DISMISSED:
+    case SHELF_ACTION_WINDOW_MINIMIZED:
+      break;
+    case SHELF_ACTION_NEW_WINDOW_CREATED:
+    case SHELF_ACTION_WINDOW_ACTIVATED: {
+      base::AutoReset<bool> reset(&should_hide_hotseat_, true);
+      UpdateVisibilityState();
+    } break;
+  }
+}
+
 void ShelfLayoutManager::OnWindowResized() {
   LayoutShelf();
 }
@@ -1042,7 +1057,8 @@
             return HotseatState::kShown;
           }
           if (visibility_state == SHELF_AUTO_HIDE) {
-            if (auto_hide_state == SHELF_AUTO_HIDE_HIDDEN)
+            if (auto_hide_state == SHELF_AUTO_HIDE_HIDDEN ||
+                should_hide_hotseat_)
               return HotseatState::kHidden;
             return HotseatState::kExtended;
           }
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index d5cdc36..6aca830 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -161,6 +161,9 @@
   void SuspendVisibilityUpdate();
   void ResumeVisiblityUpdate();
 
+  // Called when ShelfItems are interacted with in the shelf.
+  void OnShelfItemSelected(ShelfAction action);
+
   // WmDefaultLayoutManager:
   void OnWindowResized() override;
   void SetChildBounds(aura::Window* child,
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index d9585bef..e26ff51 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -26,6 +26,7 @@
 #include "ash/shelf/shelf_context_menu_model.h"
 #include "ash/shelf/shelf_controller.h"
 #include "ash/shelf/shelf_focus_cycler.h"
+#include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_menu_model_adapter.h"
 #include "ash/shelf/shelf_tooltip_manager.h"
 #include "ash/shelf/shelf_widget.h"
@@ -396,10 +397,7 @@
     return GetMirroredRect(overflow_button_->bounds());
 
   const gfx::Rect& ideal_bounds(view_model_->ideal_bounds(index));
-  views::View* view = view_model_->view_at(index);
-
-  CHECK_EQ(ShelfAppButton::kViewClassName, view->GetClassName());
-  ShelfAppButton* button = static_cast<ShelfAppButton*>(view);
+  ShelfAppButton* button = GetShelfAppButton(id);
   gfx::Rect icon_bounds = button->GetIconBounds();
   return gfx::Rect(GetMirroredXWithWidthInView(
                        ideal_bounds.x() + icon_bounds.x(), icon_bounds.width()),
@@ -449,6 +447,16 @@
          overflow_shelf()->ShouldShowTooltipForChildView(view);
 }
 
+ShelfAppButton* ShelfView::GetShelfAppButton(const ShelfID& id) {
+  const int index = model_->ItemIndexByID(id);
+  if (index < 0)
+    return nullptr;
+
+  views::View* const view = view_model_->view_at(index);
+  DCHECK_EQ(ShelfAppButton::kViewClassName, view->GetClassName());
+  return static_cast<ShelfAppButton*>(view);
+}
+
 bool ShelfView::ShouldHideTooltip(const gfx::Point& cursor_location) const {
   // There are thin gaps between launcher buttons but the tooltip shouldn't hide
   // in the gaps, but the tooltip should hide if the mouse moved totally outside
@@ -2284,10 +2292,7 @@
     return;
 
   const ShelfItem item = model_->items()[index];
-  views::View* view = view_model_->view_at(index);
-  CHECK_EQ(ShelfAppButton::kViewClassName, view->GetClassName());
-  // TODO(manucornet): Add a helper to get the button.
-  ShelfAppButton* button = static_cast<ShelfAppButton*>(view);
+  ShelfAppButton* button = GetShelfAppButton(id);
   button->ReflectItemStatus(item);
   button->SchedulePaint();
 }
@@ -2343,6 +2348,7 @@
       ink_drop->AnimateToState(views::InkDropState::ACTION_TRIGGERED);
     }
   }
+  shelf_->shelf_layout_manager()->OnShelfItemSelected(action);
   scoped_root_window_for_new_windows_.reset();
 }
 
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index 3b352f3c..e1c2efd 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -291,6 +291,9 @@
   // Different from ShouldShowTooltipForView, |view| here must be a child view.
   bool ShouldShowTooltipForChildView(const views::View* child_view) const;
 
+  // Returns the ShelfAppButton associated with |id|.
+  ShelfAppButton* GetShelfAppButton(const ShelfID& id);
+
   // Return the view model for test purposes.
   const views::ViewModel* view_model_for_test() const {
     return view_model_.get();
diff --git a/ash/system/accessibility/autoclick_scroll_view.cc b/ash/system/accessibility/autoclick_scroll_view.cc
index 3dd5ae0..ab5aab4a 100644
--- a/ash/system/accessibility/autoclick_scroll_view.cc
+++ b/ash/system/accessibility/autoclick_scroll_view.cc
@@ -23,7 +23,6 @@
 #include "ui/views/animation/ink_drop_mask.h"
 #include "ui/views/masked_targeter_delegate.h"
 #include "ui/views/view.h"
-#include "ui/views/view_class_properties.h"
 
 namespace ash {
 
@@ -156,10 +155,6 @@
     }
     SetPreferredSize(size_);
 
-    auto path = std::make_unique<SkPath>(
-        CreateCustomShapePath(gfx::Rect(GetPreferredSize())));
-    SetProperty(views::kHighlightPathKey, path.release());
-
     set_clip_path(CreateCustomShapePath(gfx::Rect(GetPreferredSize())));
     SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
   }
diff --git a/ash/system/message_center/stacked_notification_bar.cc b/ash/system/message_center/stacked_notification_bar.cc
index 36a3cb2..c7154e2 100644
--- a/ash/system/message_center/stacked_notification_bar.cc
+++ b/ash/system/message_center/stacked_notification_bar.cc
@@ -186,13 +186,6 @@
 void StackedNotificationBar::AddNotificationIcon(
     message_center::Notification* notification,
     bool at_front) {
-  SkColor accent_color = notification->accent_color() == SK_ColorTRANSPARENT
-                             ? message_center::kNotificationDefaultAccentColor
-                             : notification->accent_color();
-
-  gfx::Image masked_small_icon =
-      notification->GenerateMaskedSmallIcon(15, accent_color);
-
   views::ImageView* icon_view_ = new views::ImageView();
 
   if (at_front)
@@ -200,10 +193,14 @@
   else
     notification_icons_container_->AddChildView(icon_view_);
 
+  gfx::Image masked_small_icon = notification->GenerateMaskedSmallIcon(
+      kStackedNotificationIconSize,
+      message_center::kNotificationDefaultAccentColor);
+
   if (masked_small_icon.IsEmpty()) {
-    icon_view_->SetImage(gfx::CreateVectorIcon(message_center::kProductIcon,
-                                               kStackedNotificationIconSize,
-                                               accent_color));
+    icon_view_->SetImage(gfx::CreateVectorIcon(
+        message_center::kProductIcon, kStackedNotificationIconSize,
+        message_center::kNotificationDefaultAccentColor));
   } else {
     icon_view_->SetImage(masked_small_icon.AsImageSkia());
   }
diff --git a/ash/system/network/network_state_list_detailed_view.cc b/ash/system/network/network_state_list_detailed_view.cc
index 148f868..dd56060 100644
--- a/ash/system/network/network_state_list_detailed_view.cc
+++ b/ash/system/network/network_state_list_detailed_view.cc
@@ -398,7 +398,7 @@
       ipv6_address = device->ipv6_address->ToString();
   }
 
-  std::string ethernet_address, wifi_address;
+  std::string ethernet_address, wifi_address, cellular_address;
   if (list_type_ == LIST_TYPE_NETWORK) {
     const DeviceStateProperties* ethernet =
         model_->GetDevice(NetworkType::kEthernet);
@@ -407,23 +407,29 @@
     const DeviceStateProperties* wifi = model_->GetDevice(NetworkType::kWiFi);
     if (wifi && wifi->mac_address)
       wifi_address = *wifi->mac_address;
+    const DeviceStateProperties* cellular =
+        model_->GetDevice(NetworkType::kCellular);
+    if (cellular && cellular->mac_address)
+      cellular_address = *cellular->mac_address;
   }
 
   base::string16 bubble_text;
-  auto add_line = [&bubble_text](const std::string& address, int ids) {
-    if (!address.empty()) {
-      if (!bubble_text.empty())
-        bubble_text += base::ASCIIToUTF16("\n");
+  auto maybe_add_mac_address = [&bubble_text](const std::string& address,
+                                              int ids) {
+    if (address.empty())
+      return;
 
-      bubble_text +=
-          l10n_util::GetStringFUTF16(ids, base::UTF8ToUTF16(address));
-    }
+    if (!bubble_text.empty())
+      bubble_text += base::ASCIIToUTF16("\n");
+
+    bubble_text += l10n_util::GetStringFUTF16(ids, base::UTF8ToUTF16(address));
   };
 
-  add_line(ipv4_address, IDS_ASH_STATUS_TRAY_IP_ADDRESS);
-  add_line(ipv6_address, IDS_ASH_STATUS_TRAY_IPV6_ADDRESS);
-  add_line(ethernet_address, IDS_ASH_STATUS_TRAY_ETHERNET_ADDRESS);
-  add_line(wifi_address, IDS_ASH_STATUS_TRAY_WIFI_ADDRESS);
+  maybe_add_mac_address(ipv4_address, IDS_ASH_STATUS_TRAY_IP_ADDRESS);
+  maybe_add_mac_address(ipv6_address, IDS_ASH_STATUS_TRAY_IPV6_ADDRESS);
+  maybe_add_mac_address(ethernet_address, IDS_ASH_STATUS_TRAY_ETHERNET_ADDRESS);
+  maybe_add_mac_address(wifi_address, IDS_ASH_STATUS_TRAY_WIFI_ADDRESS);
+  maybe_add_mac_address(cellular_address, IDS_ASH_STATUS_TRAY_CELLULAR_ADDRESS);
 
   // Avoid an empty bubble in the unlikely event that there is no network
   // information at all.
diff --git a/ash/system/tray/detailed_view_delegate.cc b/ash/system/tray/detailed_view_delegate.cc
index 9654db6..ad6974e 100644
--- a/ash/system/tray/detailed_view_delegate.cc
+++ b/ash/system/tray/detailed_view_delegate.cc
@@ -22,7 +22,6 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/separator.h"
 #include "ui/views/layout/box_layout.h"
-#include "ui/views/view_class_properties.h"
 
 namespace ash {
 
@@ -77,10 +76,6 @@
         l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_PREVIOUS_MENU));
     SetBorder(views::CreateEmptyBorder(
         gfx::Insets((kTrayItemSize - image.width()) / 2)));
-
-    auto path = std::make_unique<SkPath>(
-        CreateCustomShapePath(gfx::Rect(CalculatePreferredSize())));
-    SetProperty(views::kHighlightPathKey, path.release());
   }
 
   ~BackButton() override = default;
diff --git a/ash/system/unified/collapse_button.cc b/ash/system/unified/collapse_button.cc
index 699c284..c813692b 100644
--- a/ash/system/unified/collapse_button.cc
+++ b/ash/system/unified/collapse_button.cc
@@ -11,16 +11,12 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/scoped_canvas.h"
-#include "ui/views/view_class_properties.h"
 
 namespace ash {
 
 CollapseButton::CollapseButton(views::ButtonListener* listener)
     : CustomShapeButton(listener) {
   OnEnabledChanged();
-  auto path = std::make_unique<SkPath>(
-      CreateCustomShapePath(gfx::Rect(CalculatePreferredSize())));
-  SetProperty(views::kHighlightPathKey, path.release());
 }
 
 CollapseButton::~CollapseButton() = default;
diff --git a/ash/system/unified/custom_shape_button.cc b/ash/system/unified/custom_shape_button.cc
index 58999d712..e86bfe6 100644
--- a/ash/system/unified/custom_shape_button.cc
+++ b/ash/system/unified/custom_shape_button.cc
@@ -16,12 +16,31 @@
 #include "ui/views/animation/ink_drop_impl.h"
 #include "ui/views/animation/ink_drop_mask.h"
 #include "ui/views/border.h"
+#include "ui/views/controls/highlight_path_generator.h"
+
+namespace {
+class CustomShapeButtonHighlightPathGenerator
+    : public views::HighlightPathGenerator {
+ public:
+  CustomShapeButtonHighlightPathGenerator() = default;
+
+  SkPath GetHighlightPath(const views::View* view) override {
+    return static_cast<const ash::CustomShapeButton*>(view)
+        ->CreateCustomShapePath(view->GetLocalBounds());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CustomShapeButtonHighlightPathGenerator);
+};
+}  // namespace
 
 namespace ash {
 
 CustomShapeButton::CustomShapeButton(views::ButtonListener* listener)
     : ImageButton(listener) {
   TrayPopupUtils::ConfigureTrayPopupButton(this);
+  views::HighlightPathGenerator::Install(
+      this, std::make_unique<CustomShapeButtonHighlightPathGenerator>());
 }
 
 CustomShapeButton::~CustomShapeButton() = default;
diff --git a/ash/wm/overview/overview_controller.cc b/ash/wm/overview/overview_controller.cc
index de7b8c5..76e8f74 100644
--- a/ash/wm/overview/overview_controller.cc
+++ b/ash/wm/overview/overview_controller.cc
@@ -231,7 +231,7 @@
   return !start_animations_.empty();
 }
 
-bool OverviewController::IsCompletingShutdownAnimations() {
+bool OverviewController::IsCompletingShutdownAnimations() const {
   return !delayed_animations_.empty();
 }
 
diff --git a/ash/wm/overview/overview_controller.h b/ash/wm/overview/overview_controller.h
index 6457c8e0..772ecbf5d 100644
--- a/ash/wm/overview/overview_controller.h
+++ b/ash/wm/overview/overview_controller.h
@@ -60,7 +60,7 @@
 
   // Returns true if overview has been shutdown, but is still animating to the
   // end state ui.
-  bool IsCompletingShutdownAnimations();
+  bool IsCompletingShutdownAnimations() const;
 
   // Pause or unpause the occlusion tracker. Resets the unpause delay if we were
   // already in the process of unpausing.
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index 3ebe8a5..149313f 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -586,6 +586,13 @@
   cannot_snap_widget_->SetBoundsCenteredIn(bounds, /*animate=*/false);
 }
 
+void OverviewItem::HideCannotSnapWarning() {
+  if (!cannot_snap_widget_)
+    return;
+  DoSplitviewOpacityAnimation(cannot_snap_widget_->GetNativeWindow()->layer(),
+                              SPLITVIEW_ANIMATION_OVERVIEW_ITEM_FADE_OUT);
+}
+
 void OverviewItem::OnSelectorItemDragStarted(OverviewItem* item) {
   is_being_dragged_ = (item == this);
   caption_container_view_->SetHeaderVisibility(
diff --git a/ash/wm/overview/overview_item.h b/ash/wm/overview/overview_item.h
index 06cddcf..0d8aa67 100644
--- a/ash/wm/overview/overview_item.h
+++ b/ash/wm/overview/overview_item.h
@@ -108,6 +108,10 @@
   // window cannot be snapped.
   void UpdateCannotSnapWarningVisibility();
 
+  // Hides the cannot snap warning (if it was showing) until the next call to
+  // |UpdateCannotSnapWarningVisibility|.
+  void HideCannotSnapWarning();
+
   // Called when a OverviewItem on any grid is dragged. Hides the close button
   // when a drag is started, and reshows it when a drag is finished.
   // Additionally hides the title and window icon if |item| is this.
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 652bd0e..c7838c02 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -78,6 +78,7 @@
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/test/display_manager_test_api.h"
 #include "ui/events/event_utils.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/transform.h"
@@ -4086,6 +4087,108 @@
   EXPECT_EQ(0.f, unsnappable_layer->opacity());
 }
 
+// Verify that during "normal" dragging from overview (not drag-to-close), the
+// dragged item's unsnappable indicator is temporarily suppressed.
+TEST_P(SplitViewOverviewSessionTest,
+       OverviewUnsnappableIndicatorVisibilityWhileDragging) {
+  ui::GestureConfiguration* gesture_config =
+      ui::GestureConfiguration::GetInstance();
+  gesture_config->set_long_press_time_in_ms(1);
+  gesture_config->set_show_press_delay_in_ms(1);
+
+  std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
+  std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow();
+  ToggleOverview();
+  ASSERT_TRUE(overview_controller()->InOverviewSession());
+  split_view_controller()->SnapWindow(snapped_window.get(),
+                                      SplitViewController::LEFT);
+  ASSERT_TRUE(split_view_controller()->InSplitViewMode());
+  OverviewItem* unsnappable_overview_item =
+      GetOverviewItemForWindow(unsnappable_window.get());
+  ASSERT_TRUE(unsnappable_overview_item->cannot_snap_widget_for_testing());
+  ui::Layer* unsnappable_layer =
+      unsnappable_overview_item->cannot_snap_widget_for_testing()
+          ->GetNativeWindow()
+          ->layer();
+  ASSERT_EQ(1.f, unsnappable_layer->opacity());
+
+  // Test that the unsnappable label is temporarily suppressed during mouse
+  // dragging.
+  ui::test::EventGenerator* generator = GetEventGenerator();
+  const gfx::Point drag_starting_point = gfx::ToRoundedPoint(
+      unsnappable_overview_item->target_bounds().CenterPoint());
+  generator->set_current_screen_location(drag_starting_point);
+  generator->PressLeftButton();
+  using DragBehavior = OverviewWindowDragController::DragBehavior;
+  EXPECT_EQ(
+      DragBehavior::kUndefined,
+      overview_session()->window_drag_controller()->current_drag_behavior());
+  EXPECT_EQ(1.f, unsnappable_layer->opacity());
+  generator->MoveMouseBy(0, 20);
+  EXPECT_EQ(
+      DragBehavior::kNormalDrag,
+      overview_session()->window_drag_controller()->current_drag_behavior());
+  EXPECT_EQ(0.f, unsnappable_layer->opacity());
+  generator->ReleaseLeftButton();
+  EXPECT_EQ(1.f, unsnappable_layer->opacity());
+
+  // Test that the unsnappable label is temporarily suppressed during "normal"
+  // touch dragging (not drag-to-close).
+  generator->set_current_screen_location(drag_starting_point);
+  generator->PressTouch();
+  {
+    base::RunLoop run_loop;
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(),
+        base::TimeDelta::FromMilliseconds(2));
+    run_loop.Run();
+  }
+  EXPECT_EQ(
+      DragBehavior::kNormalDrag,
+      overview_session()->window_drag_controller()->current_drag_behavior());
+  EXPECT_EQ(0.f, unsnappable_layer->opacity());
+  generator->MoveTouchBy(20, 0);
+  generator->ReleaseTouch();
+  EXPECT_EQ(1.f, unsnappable_layer->opacity());
+
+  // Test that the unsnappable label reappears if "normal" touch dragging (not
+  // drag-to-close) ends when the item has not been actually dragged anywhere.
+  // This case improves test coverage because it is handled in
+  // |OverviewWindowDragController::ResetGesture| instead of
+  // |OverviewWindowDragController::CompleteNormalDrag|.
+  generator->set_current_screen_location(drag_starting_point);
+  generator->PressTouch();
+  {
+    base::RunLoop run_loop;
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(),
+        base::TimeDelta::FromMilliseconds(2));
+    run_loop.Run();
+  }
+  EXPECT_EQ(
+      DragBehavior::kNormalDrag,
+      overview_session()->window_drag_controller()->current_drag_behavior());
+  EXPECT_EQ(0.f, unsnappable_layer->opacity());
+  generator->ReleaseTouch();
+  EXPECT_EQ(1.f, unsnappable_layer->opacity());
+
+  // Test that the unsnappable label persists in drag-to-close mode.
+  generator->set_current_screen_location(drag_starting_point);
+  generator->PressTouch();
+  // Use small increments otherwise a fling event will be fired.
+  for (int j = 0; j < 20; ++j)
+    generator->MoveTouchBy(0, 1);
+  EXPECT_EQ(
+      DragBehavior::kDragToClose,
+      overview_session()->window_drag_controller()->current_drag_behavior());
+  // Drag-to-close mode affects the opacity of the whole overview item,
+  // including the unsnappable label.
+  EXPECT_EQ(unsnappable_overview_item->GetWindow()->layer()->opacity(),
+            unsnappable_layer->opacity());
+  generator->ReleaseTouch();
+  EXPECT_EQ(1.f, unsnappable_layer->opacity());
+}
+
 // Test that when splitview mode and overview mode are both active at the same
 // time, dragging divider behaviors are correct.
 TEST_P(SplitViewOverviewSessionTest, DragDividerToExitTest) {
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index ee9c5a5..9463ed4 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -239,6 +239,7 @@
         CanSnapInSplitview(item_->GetWindow()) ? IndicatorState::kDragArea
                                                : IndicatorState::kCannotSnap,
         gfx::ToRoundedPoint(location_in_screen));
+    item_->HideCannotSnapWarning();
 
     // Update the split view divider bar status if necessary. If splitview is
     // active when dragging the overview window, the split divider bar should be
@@ -329,6 +330,7 @@
     if (should_allow_split_view_) {
       overview_session_->SetSplitViewDragIndicatorsIndicatorState(
           IndicatorState::kNone, gfx::Point());
+      item_->UpdateCannotSnapWarningVisibility();
     }
   }
   overview_session_->PositionWindows(/*animate=*/true);
@@ -514,6 +516,7 @@
     UpdateDragIndicatorsAndOverviewGrid(location_in_screen);
     overview_session_->SetSplitViewDragIndicatorsIndicatorState(
         IndicatorState::kNone, rounded_screen_point);
+    item_->UpdateCannotSnapWarningVisibility();
   }
 
   // This function has multiple exit positions, at each we must update the desks
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index 5a0e70f9..6926594f 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -11,8 +11,27 @@
 #include "base/allocator/partition_allocator/partition_bucket.h"
 #include "base/allocator/partition_allocator/partition_cookie.h"
 #include "base/allocator/partition_allocator/partition_freelist_entry.h"
+#include "base/allocator/partition_allocator/random.h"
 #include "base/logging.h"
 
+namespace {
+
+// Returns true if we've hit the end of a random-length period. We don't want to
+// invoke `RandomValue` too often, because we call this function in a hot spot
+// (`Free`), and `RandomValue` incurs the cost of atomics.
+#if !DCHECK_IS_ON()
+bool RandomPeriod() {
+  static thread_local uint8_t counter = 0;
+  if (UNLIKELY(counter == 0)) {
+    counter = base::RandomValue();
+  }
+  counter--;
+  return counter == 0;
+}
+#endif
+
+}  // namespace
+
 namespace base {
 namespace internal {
 
@@ -201,23 +220,29 @@
 }
 
 ALWAYS_INLINE void PartitionPage::Free(void* ptr) {
-#if DCHECK_IS_ON()
   size_t slot_size = this->bucket->slot_size;
   const size_t raw_size = get_raw_size();
   if (raw_size) {
     slot_size = raw_size;
   }
 
+#if DCHECK_IS_ON()
   // If these asserts fire, you probably corrupted memory.
   PartitionCookieCheckValue(ptr);
   PartitionCookieCheckValue(reinterpret_cast<char*>(ptr) + slot_size -
                             kCookieSize);
 
   memset(ptr, kFreedByte, slot_size);
+#else
+  // `memset` only once in a while.
+  if (UNLIKELY(RandomPeriod())) {
+    memset(ptr, kFreedByte, slot_size);
+  }
 #endif
 
   DCHECK(this->num_allocated_slots);
-  CHECK(ptr != freelist_head);  // Catches an immediate double free.
+  // Catches an immediate double free.
+  CHECK(ptr != freelist_head);
   // Look for double free one level deeper in debug.
   DCHECK(!freelist_head || ptr != internal::PartitionFreelistEntry::Transform(
                                       freelist_head->next));
diff --git a/base/allocator/partition_allocator/random.h b/base/allocator/partition_allocator/random.h
index 85cb66d..a9aaa7f 100644
--- a/base/allocator/partition_allocator/random.h
+++ b/base/allocator/partition_allocator/random.h
@@ -15,7 +15,7 @@
 // `base::RandUint64` which is very unpredictable, but which is expensive due to
 // the need to call into the kernel. Therefore this generator uses a fast,
 // entirely user-space function after initialization.
-uint32_t RandomValue();
+BASE_EXPORT uint32_t RandomValue();
 
 // Sets the seed for the random number generator to a known value, to cause the
 // RNG to generate a predictable sequence of outputs. May be called multiple
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h
index dcb32a5..8cbbc62 100644
--- a/base/trace_event/builtin_categories.h
+++ b/base/trace_event/builtin_categories.h
@@ -178,6 +178,7 @@
   X(TRACE_DISABLED_BY_DEFAULT("gpu.device"))                             \
   X(TRACE_DISABLED_BY_DEFAULT("gpu.service"))                            \
   X(TRACE_DISABLED_BY_DEFAULT("ipc.flow"))                               \
+  X(TRACE_DISABLED_BY_DEFAULT("java-heap-profiler"))                     \
   X(TRACE_DISABLED_BY_DEFAULT("layer-element"))                          \
   X(TRACE_DISABLED_BY_DEFAULT("lifecycles"))                             \
   X(TRACE_DISABLED_BY_DEFAULT("loading"))                                \
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
index e89597c..7e42cfc 100644
--- a/base/trace_event/malloc_dump_provider.cc
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -134,7 +134,10 @@
 // TODO(fuchsia): Port, see https://crbug.com/706592.
 #else
   struct mallinfo info = mallinfo();
-  DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
+#if !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER)
+  // Sanitizers override mallinfo.
+  DCHECK_GT(static_cast<int>(info.uordblks), 0);
+#endif
 
   // In case of Android's jemalloc |arena| is 0 and the outer pages size is
   // reported by |hblkhd|. In case of dlmalloc the total is given by
diff --git a/build/android/bytecode/BUILD.gn b/build/android/bytecode/BUILD.gn
index fa911f6..8851753 100644
--- a/build/android/bytecode/BUILD.gn
+++ b/build/android/bytecode/BUILD.gn
@@ -11,7 +11,6 @@
     "java/org/chromium/bytecode/AssertionEnablerClassAdapter.java",
     "java/org/chromium/bytecode/ByteCodeProcessor.java",
     "java/org/chromium/bytecode/ClassPathValidator.java",
-    "java/org/chromium/bytecode/ConstantPoolReferenceReader.java",
     "java/org/chromium/bytecode/CustomClassLoaderClassWriter.java",
     "java/org/chromium/bytecode/CustomResourcesClassAdapter.java",
     "java/org/chromium/bytecode/ThreadAssertionClassAdapter.java",
diff --git a/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java b/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java
index 2a0ea504f..4a56332 100644
--- a/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java
+++ b/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java
@@ -63,7 +63,6 @@
     private static ClassLoader sDirectClassPathClassLoader;
     private static ClassLoader sFullClassPathClassLoader;
     private static Set<String> sFullClassPathJarPaths;
-    private static String sGenerateClassDepsPath;
     private static ClassPathValidator sValidator;
 
     private static class EntryDataPair {
@@ -257,7 +256,6 @@
         sShouldUseCustomResources = args[currIndex++].equals("--enable-custom-resources");
         sShouldUseThreadAnnotations = args[currIndex++].equals("--enable-thread-annotations");
         sShouldCheckClassPath = args[currIndex++].equals("--enable-check-class-path");
-        sGenerateClassDepsPath = args[currIndex++];
         int sdkJarsLength = Integer.parseInt(args[currIndex++]);
         List<String> sdkJarPaths =
                 Arrays.asList(Arrays.copyOfRange(args, currIndex, currIndex + sdkJarsLength));
@@ -280,13 +278,6 @@
         sFullClassPathJarPaths.addAll(
                 Arrays.asList(Arrays.copyOfRange(args, currIndex, args.length)));
 
-        // Write list of references from Java class constant pools to specified output file
-        // sGenerateClassDepsPath. This is needed for keep rule generation for async DFMs.
-        if (!sGenerateClassDepsPath.isEmpty()) {
-            ConstantPoolReferenceReader.writeConstantPoolRefsToFile(
-                    sFullClassPathJarPaths, sGenerateClassDepsPath);
-        }
-
         sFullClassPathClassLoader = loadJars(sFullClassPathJarPaths);
         sFullClassPathJarPaths.removeAll(directClassPathJarPaths);
 
diff --git a/build/android/bytecode/java/org/chromium/bytecode/ConstantPoolReferenceReader.java b/build/android/bytecode/java/org/chromium/bytecode/ConstantPoolReferenceReader.java
deleted file mode 100644
index e2cbd397..0000000
--- a/build/android/bytecode/java/org/chromium/bytecode/ConstantPoolReferenceReader.java
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.bytecode;
-
-import org.objectweb.asm.ClassReader;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedWriter;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-/**
- * Compiles list of references from all Java .class files in given jar paths by
- * reading from the constant pool, and writes this list to an output file.
- * This list is used for keep rule generation for maintaining compatibility between
- * async DFMs and synchronous modules.
- */
-public class ConstantPoolReferenceReader {
-    private static final String CLASS_FILE_SUFFIX = ".class";
-    private static final int BUFFER_SIZE = 16384;
-
-    // Constants representing Java constant pool tags
-    // See https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4
-    private static final int FIELD_REF_TAG = 9;
-    private static final int METHOD_REF_TAG = 10;
-    private static final int INTERFACE_METHOD_REF_TAG = 11;
-
-    private static byte[] readAllBytes(InputStream inputStream) throws IOException {
-        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-        int numRead = 0;
-        byte[] data = new byte[BUFFER_SIZE];
-        while ((numRead = inputStream.read(data, 0, data.length)) != -1) {
-            buffer.write(data, 0, numRead);
-        }
-        return buffer.toByteArray();
-    }
-
-    /**
-     * Given a set of paths, generates references used to produce Proguard keep rules
-     * necessary for asynchronous DFMs.
-     * It reads all references stored in constant pools of Java classes from
-     * the specified jar paths and writes them to an output file.
-     * References written to the specified file can be converted to a
-     * corresponding set of Proguard keep rules using the
-     * constant_pool_refs_to_keep_rules.py script.
-     *
-     * @param jarPaths Set of paths specifying Java files to read constant pool
-     * references from.
-     * @param outputFilePath File path to write output to.
-     */
-    public static void writeConstantPoolRefsToFile(Set<String> jarPaths, String outputFilePath) {
-        HashSet<String> classReferences = new HashSet<>();
-
-        for (String jarPath : jarPaths) {
-            try (ZipInputStream inputStream = new ZipInputStream(
-                         new BufferedInputStream(new FileInputStream(jarPath)))) {
-                ZipEntry entry;
-                while ((entry = inputStream.getNextEntry()) != null) {
-                    if (entry.isDirectory() || !entry.getName().endsWith(CLASS_FILE_SUFFIX)) {
-                        continue;
-                    }
-                    byte[] data = readAllBytes(inputStream);
-                    ClassReader reader = new ClassReader(data);
-                    classReferences.addAll(collectConstantPoolClassReferences(reader));
-                }
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        try {
-            BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilePath));
-            for (String ref : classReferences) {
-                writer.append(ref);
-                writer.append("\n");
-            }
-            writer.close();
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Given a ClassReader, return a set of all super classes, implemented interfaces and
-     * members by reading from the associated class's constant pool.
-     *
-     * @param classReader .class file interface for reading the constant pool.
-     */
-    private static Set<String> collectConstantPoolClassReferences(ClassReader classReader) {
-        char[] charBuffer = new char[classReader.getMaxStringLength()];
-        HashSet<String> classReferences = new HashSet<>();
-
-        classReferences.add(classReader.getSuperName());
-        classReferences.addAll(Arrays.asList(classReader.getInterfaces()));
-
-        // According to the Java spec, the constant pool is indexed from 1 to constant_pool_count -
-        // 1. See https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4
-        StringBuilder refInfoString = new StringBuilder();
-        for (int i = 1; i < classReader.getItemCount(); i++) {
-            int offset = classReader.getItem(i);
-            if (offset <= 0) {
-                continue;
-            }
-            int constantType = classReader.readByte(offset - 1);
-            if (offset > 0
-                    && (constantType == METHOD_REF_TAG || constantType == FIELD_REF_TAG
-                            || constantType == INTERFACE_METHOD_REF_TAG)) {
-                // Read the corresponding class ref and member info from the constant pool.
-                int classIndex = classReader.readUnsignedShort(offset);
-                int classStartIndex = classReader.getItem(classIndex);
-                // Class index is a 2-byte quantity, nameAndTypeIndex is stored sequentially after.
-                int nameAndTypeIndex = classReader.readUnsignedShort(offset + 2);
-                int nameAndTypeStartIndex = classReader.getItem(nameAndTypeIndex);
-
-                // Get member's containing class's name, member's name, and member's details (type,
-                // return type, and argument types).
-                refInfoString.append(classReader.readUTF8(classStartIndex, charBuffer));
-                refInfoString.append(",");
-                refInfoString.append(classReader.readUTF8(nameAndTypeStartIndex, charBuffer));
-                refInfoString.append(",");
-                refInfoString.append(classReader.readUTF8(nameAndTypeStartIndex + 2, charBuffer));
-
-                classReferences.add(refInfoString.toString());
-                refInfoString.setLength(0);
-            }
-        }
-
-        return classReferences;
-    }
-}
\ No newline at end of file
diff --git a/build/android/constant_pool_refs_to_keep_rules.py b/build/android/constant_pool_refs_to_keep_rules.py
deleted file mode 100644
index b2452d7..0000000
--- a/build/android/constant_pool_refs_to_keep_rules.py
+++ /dev/null
@@ -1,223 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-This script is used to convert a list of references to corresponding ProGuard
-keep rules, for the purposes of maintaining compatibility between async DFMs
-and synchronously proguarded modules.
-This script take an input file generated from
-//build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java
-during the build phase of an async module.
-"""
-
-from collections import defaultdict
-import argparse
-import sys
-
-# Classes in _IGNORED_PACKAGES do not need explicit keep rules because they are
-# system APIs and are already included in ProGuard configs.
-_IGNORED_PACKAGES = ['java', 'android', 'org.w3c', 'org.xml', 'dalvik']
-
-# Classes in _WHITELIST_PACKAGES are support libraries compiled into chrome
-# that must bypass the _IGNORED_PACKAGES.
-_WHITELIST_PACKAGES = ['android.support']
-
-# TODO(https://crbug.com/968769): Filter may be too broad.
-# Classes in _DFM_FEATURES will be excluded from "keep all members" rule.
-_DFM_FEATURES = [
-    'org.chromium.chrome.autofill_assistant', 'org.chromium.chrome.tab_ui',
-    'org.chromium.chrome.browser.tasks.tab_management', 'org.chromium.chrome.vr'
-]
-
-# Mapping for translating Java bytecode type identifiers to source code type
-# identifiers.
-_TYPE_IDENTIFIER_MAP = {
-    'V': 'void',
-    'Z': 'boolean',
-    'B': 'byte',
-    'S': 'short',
-    'C': 'char',
-    'I': 'int',
-    'J': 'long',
-    'F': 'float',
-    'D': 'double',
-}
-
-
-# Translates DEX TypeDescriptor of the first type found in a given string to
-# its source code type identifier, as described in
-# https://source.android.com/devices/tech/dalvik/dex-format#typedescriptor,
-# and returns the translated type and the starting index of the next type
-# (if present).
-def translate_single_type(typedesc):
-  array_count = 0
-  translated = ''
-  next_index = 0
-
-  # In the constant pool, fully qualified names (prefixed by 'L') have a
-  # trailing ';' if they are describing the type/return type of a symbol,
-  # or the type of arguments passed to a symbol. TypeDescriptor representing
-  # primitive types do not have trailing ';'s in any circumstances.
-  for i, c in enumerate(typedesc):
-    if c == '[':
-      array_count += 1
-      continue
-    if c == 'L':
-      # Fully qualified names have no trailing ';' if they are describing the
-      # containing class of a reference.
-      next_index = typedesc.find(';')
-      if next_index == -1:
-        next_index = len(typedesc)
-      translated = typedesc[i + 1:next_index]
-      break
-    else:
-      translated = _TYPE_IDENTIFIER_MAP[c]
-      next_index = i
-      break
-
-  translated += '[]' * array_count
-  return translated, next_index + 1
-
-
-# Convert string of method argument types read from constant pool to
-# corresponding list of srouce code type identifiers.
-def parse_args_list(args_list):
-  parsed_args = []
-  start_index = 0
-
-  while start_index < len(args_list):
-    args_list = args_list[start_index:]
-    translated_arg, start_index = translate_single_type(args_list)
-    parsed_args.append(translated_arg)
-
-  return parsed_args
-
-
-def add_to_refs(class_name, keep_entry, dep_refs):
-  # Add entry to class's keep rule if entry is not the empty string
-  if class_name in dep_refs and keep_entry:
-    dep_refs[class_name].append(keep_entry)
-  else:
-    dep_refs[class_name] = [keep_entry]
-
-
-def should_include_class_path(class_path):
-  """ Check whether a class_path should be added as keep rule.
-      Conditions:
-        - Class is auto-generated (Lambdas/Nested, for example $)
-        - Class is not in a DFM Module
-        - Class is not in a black/white listed package
-    """
-  nested_class = '$' in class_path
-  not_in_dfm = all(not class_path.startswith(f) for f in _DFM_FEATURES)
-  allowed_packages = not (any(
-      class_path.startswith(p)
-      for p in _IGNORED_PACKAGES) and all(not class_path.startswith(p)
-                                          for p in _WHITELIST_PACKAGES))
-  return nested_class or (not_in_dfm and allowed_packages)
-
-
-def main(argv):
-  dep_refs = defaultdict(list)
-  extended_and_implemented_classes = set()
-
-  parser = argparse.ArgumentParser()
-  parser.add_argument(
-      '--input-file',
-      required=True,
-      help='Path to constant pool reference output.')
-  parser.add_argument(
-      '--output-file',
-      required=True,
-      help='Path to write corresponding keep rules to')
-  args = parser.parse_args(argv[1:])
-
-  with open(args.input_file, 'r') as constant_pool_refs:
-    for line in constant_pool_refs:
-      line = line.rstrip().replace('/', '.')
-      # Ignore any references specified by the list of
-      # _IGNORED_PACKAGES and not in _WHITELIST_PACKAGES.
-      if (any(line.startswith(p) for p in _IGNORED_PACKAGES)
-          and all(not line.startswith(p) for p in _WHITELIST_PACKAGES)):
-        continue
-
-      reflist = line.split(',')
-
-      # Lines denoting super classes and implemented interface references do
-      # not contain additional information and thus have reflist size 1.
-      # Store these as a separate set as they require full keep rules.
-      if len(reflist) == 1:
-        extended_and_implemented_classes.add(reflist[0])
-        continue
-
-      class_name = reflist[0]
-      member_name = reflist[1]
-      member_info = reflist[2]
-      keep_entry = ''
-
-      # When testing with the VR module, all class names read from constant
-      # pool output that were prefixed with '[' matched references to the
-      # overridden clone() method of the Object class. These seem to correspond
-      # to Java enum types defined within classes.
-      # It is not entirely clear whether or not this always represents
-      # an enum, why enums would be represented as such in the constant pool,
-      # or how we should go about keeping these references. For the moment,
-      # ignoring these references does not impact compatibility between
-      # modules.
-      if class_name.startswith('['):
-        continue
-
-      # Ignore R(esources) files that are from the same module.
-      if ('$' in class_name
-          and any(class_name.startswith(f) for f in _DFM_FEATURES)):
-        continue
-
-      # If member_info starts with '(', member is a method, otherwise member
-      # is a field.
-      # Format keep entries as per ProGuard documentation
-      # guardsquare.com/en/products/proguard/manual/usage#classspecification.
-      if member_info.startswith('('):
-        args_list, return_type = member_info.split(')')
-        args_list = parse_args_list(args_list[1:])
-        if member_name == '<init>':
-          # No return type specified for constructors.
-          return_type = ''
-        else:
-          return_type = translate_single_type(return_type)[0]
-
-        # Include types of function arguments.
-        for arg_type in args_list:
-          if should_include_class_path(arg_type):
-            extended_and_implemented_classes.add(arg_type)
-
-        # Include the actual class when it's a constructor.
-        if member_name == '<init>':
-          if should_include_class_path(class_name):
-            extended_and_implemented_classes.add(class_name)
-          continue
-
-        keep_entry = '%s %s(%s);' % (return_type, member_name,
-                                     ', '.join(args_list))
-      else:
-        keep_entry = '%s %s;' % (translate_single_type(member_info)[0],
-                                 member_name)
-
-      dep_refs[class_name].append(keep_entry)
-
-  with open(args.output_file, 'w') as keep_rules:
-    # Write super classes and implemented interfaces to keep rules.
-    for super_class in sorted(extended_and_implemented_classes):
-      keep_rules.write('-keep class %s { *; }\n' % (super_class.rstrip()))
-      keep_rules.write('\n')
-    # Write all other class references to keep rules.
-    for c in sorted(dep_refs.iterkeys()):
-      if c in extended_and_implemented_classes:
-        continue
-      class_keeps = '\n  '.join(dep_refs[c])
-      keep_rules.write('-keep class %s {\n  %s\n}\n' % (c, class_keeps))
-      keep_rules.write('\n')
-
-
-if __name__ == '__main__':
-  main(sys.argv)
diff --git a/build/android/constant_pool_refs_to_keep_rules_test.py b/build/android/constant_pool_refs_to_keep_rules_test.py
deleted file mode 100644
index 6f281e2..0000000
--- a/build/android/constant_pool_refs_to_keep_rules_test.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import unittest
-import re
-import os
-
-
-class TestProguardRuleGeneration(unittest.TestCase):
-  """
-  This script is used to test a ProGuard keep rules for the purposes
-  of maintaining compatibility between async DFMs and synchronously
-  proguarded modules.
-
-  The rules are often generated by constant_pool_refs_to_keep_rules.py
-
-  This test can be run manually. Example:
-  python build/android/constant_pool_refs_to_keep_rules_test.py -v
-  """
-
-  # Make sure this variable is set accordingly.
-  # It should point to a proguard file.
-  PROGUARD_FILE_PATH = os.path.join(
-      os.path.dirname(__file__),
-      "../../chrome/android/features/tab_ui/proguard_async.flags")
-
-  def test_TabUI_HasRules(self):
-    """
-    Ensures that a few of the rules used in tabs_ui module are included.
-    Although this is far from 100% deterministic, these rules are
-    created by code that exercise different parts of the rule generation code.
-    """
-
-    rules = set()
-    with open(self.PROGUARD_FILE_PATH, 'r') as proguard_rules:
-      for line in proguard_rules:
-        if line.startswith('-keep'):
-          rule = re.search('class (.+?) {', line).group(1)
-          rules.add(rule)
-
-    # The following rules test most of the use cases for
-    # rules that can be added automatically.
-    self.assertIn('org.chromium.ui.modelutil.PropertyModel', rules)
-    self.assertIn('org.chromium.ui.modelutil.PropertyModel', rules)
-    self.assertIn('org.chromium.ui.modelutil.PropertyKey', rules)
-    self.assertIn('org.chromium.chrome.browser.toolbar.ToolbarManager', rules)
-    self.assertIn('org.chromium.base.Supplier', rules)
-    self.assertIn('android.support.v7.widget.helper.ItemTouchHelper', rules)
-    self.assertIn(
-        'android.support.v7.widget.helper.ItemTouchHelper$SimpleCallback',
-        rules)
-    self.assertIn('android.support.v7.widget.helper.ItemTouchHelper$Callback',
-                  rules)
-    self.assertIn('android.support.v4.content.ContextCompat', rules)
-    self.assertIn('android.support.v7.widget.GridLayoutManager', rules)
-    self.assertIn('android.support.v4.content.res.ResourcesCompat', rules)
-    self.assertIn(
-        'org.chromium.chrome.browser.tasks.tabgroup.TabGroupModelFilter', rules)
-    self.assertIn('android.support.v7.widget.RecyclerView$ViewHolder', rules)
-    self.assertIn('android.support.v7.widget.RecyclerView', rules)
-    self.assertIn('org.chromium.ui.modelutil.SimpleRecyclerViewMcpBase', rules)
-    self.assertIn('org.chromium.ui.modelutil.RecyclerViewAdapter', rules)
-
-    # The following rules need to be added manually.
-    self.assertNotIn(
-        'org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager' +
-        '$FullscreenListener$$CC', rules)
-    self.assertNotIn(
-        'org.chromium.chrome.browser.widget.bottomsheet.BottomSheet' +
-        '$BottomSheetContent$$CC', rules)
-    self.assertNotIn('org.chromium.ui.widget.RoundedCornerImageView', rules)
-    self.assertNotIn(
-        'android.support.v4.graphics.drawable.RoundedBitmapDrawable', rules)
-
-  def test_TabUI_HasNoDuplicateRules(self):
-    """
-    Ensures that there are no duplicate keep rules
-    """
-
-    rules = set()
-    with open(self.PROGUARD_FILE_PATH, 'r') as proguard_rules:
-      for line in proguard_rules:
-        if line.startswith('-keep'):
-          rule = re.search('class (.+?) {', line).group(1)
-          self.assertNotIn(rule, rules)
-          rules.add(rule)
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/build/android/gyp/bytecode_processor.py b/build/android/gyp/bytecode_processor.py
index e1bfefc..76775d3 100755
--- a/build/android/gyp/bytecode_processor.py
+++ b/build/android/gyp/bytecode_processor.py
@@ -36,7 +36,6 @@
   _AddSwitch(parser, '--enable-assert')
   _AddSwitch(parser, '--enable-thread-annotations')
   _AddSwitch(parser, '--enable-check-class-path')
-  parser.add_argument('--enable-class-deps-output', default='')
   args = parser.parse_args(argv)
 
   sdk_jars = build_utils.ParseGnList(args.sdk_classpath_jars)
@@ -58,7 +57,6 @@
       args.script, args.input_jar, args.output_jar, verbose, args.is_prebuilt,
       args.enable_assert, args.enable_custom_resources,
       args.enable_thread_annotations, args.enable_check_class_path,
-      args.enable_class_deps_output,
       str(len(sdk_jars))
   ] + sdk_jars + [str(len(direct_jars))] + direct_jars + extra_classpath_jars)
   subprocess.check_call(cmd)
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
index 4f7b992..091d7d7 100755
--- a/build/android/gyp/proguard.py
+++ b/build/android/gyp/proguard.py
@@ -111,8 +111,7 @@
   parser.add_argument(
       '--verbose', '-v', action='store_true', help='Print all ProGuard output')
   parser.add_argument(
-      '--repackage-classes',
-      help='Unique package name given to an asynchronously proguarded module')
+      '--repackage-classes', help='Package all optimized classes are put in.')
   parser.add_argument(
       '--disable-outlining',
       action='store_true',
diff --git a/build/android/pylib/local/emulator/avd.py b/build/android/pylib/local/emulator/avd.py
index f3ab4f99..e08d9a9 100644
--- a/build/android/pylib/local/emulator/avd.py
+++ b/build/android/pylib/local/emulator/avd.py
@@ -231,6 +231,9 @@
         config_ini_file.write(
             textwrap.dedent("""\
                 disk.dataPartition.size=4G
+                hw.lcd.density=160
+                hw.lcd.height=960
+                hw.lcd.width=480
                 """))
 
       # Start & stop the AVD.
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index dff3439..fb980128 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1529,10 +1529,8 @@
     _desugar = defined(invoker.supports_android) && invoker.supports_android
     _jacoco_instrument = invoker.jacoco_instrument
 
-    _enable_class_deps_output = defined(invoker.enable_class_deps_output)
     _enable_bytecode_rewriter =
-        _enable_assert || _enable_custom_resources ||
-        _enable_thread_annotations || _enable_class_deps_output
+        _enable_assert || _enable_custom_resources || _enable_thread_annotations
     _is_prebuilt = defined(invoker.is_prebuilt) && invoker.is_prebuilt
     _enable_bytecode_checks = !defined(invoker.enable_bytecode_checks) ||
                               invoker.enable_bytecode_checks
@@ -1548,7 +1546,6 @@
     if (defined(invoker.enable_bytecode_rewriter)) {
       not_needed([
                    "_enable_assert",
-                   "_enable_class_deps_output",
                    "_enable_custom_resources",
                    "_enable_thread_annotations",
                  ])
@@ -1616,10 +1613,6 @@
         if (_enable_bytecode_checks) {
           args += [ "--enable-check-class-path" ]
         }
-        if (_enable_class_deps_output) {
-          args += [ "--enable-class-deps-output" ] +
-                  [ invoker.enable_class_deps_output ]
-        }
         args += [
           "--direct-classpath-jars",
           "@FileArg($_rebased_build_config:javac:classpath)",
@@ -3628,7 +3621,6 @@
                                  [
                                    "enable_bytecode_checks",
                                    "enable_bytecode_rewriter",
-                                   "enable_class_deps_output",
                                    "jar_excluded_patterns",
                                    "jar_included_patterns",
                                  ])
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 15fe274..aeff5719 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2779,7 +2779,6 @@
                                "base_module_target",
                                "chromium_code",
                                "classpath_deps",
-                               "enable_class_deps_output",
                                "jacoco_never_instrument",
                                "java_files",
                                "javac_args",
@@ -3508,7 +3507,6 @@
                                "data_deps",
                                "deps",
                                "enable_chromium_linker_tests",
-                               "enable_class_deps_output",
                                "enable_multidex",
                                "generate_buildconfig_java",
                                "generate_final_jni",
@@ -4387,13 +4385,6 @@
   #      module name (which cannot be 'base', since this is reserved for the
   #      base module), and an 'apk_target' field that specified the
   #      corresponding android_apk target name the module is modeled on.
-  #      A scope may have an additional field, 'proguard_async', that
-  #      specifies whether or not the module is asynchronous. This field should
-  #      be set to true if the module is asynchronous, and set to false or left
-  #      undefined otherwise.
-  #      Async modules are those that are proguarded in a separate build step.
-  #      This ensures that changes to these modules do not change the base
-  #      module.
   #
   #    enable_language_splits: Optional. If true, enable APK splits based
   #      on languages.
@@ -4476,7 +4467,7 @@
     _rebased_base_module_build_config =
         rebase_path(_base_module_build_config, root_build_dir)
 
-    _sync_modules = [
+    _modules = [
       {
         name = "base"
         module_target = invoker.base_module_target
@@ -4485,8 +4476,6 @@
       },
     ]
 
-    _async_modules = []
-
     _proguard_enabled =
         defined(invoker.proguard_enabled) && invoker.proguard_enabled
     _enable_multidex =
@@ -4507,10 +4496,7 @@
         _sync_dex_target = "${target_name}__sync_dex"
         _sync_dex_target_dep = ":$_sync_dex_target"
       }
-
-      # TODO(crbug.com/938635): Combine synchronous proguard run mapping file
-      # and asynchronous proguard run mapping files into single .mapping.
-      _sync_proguard_mapping_path = "${_bundle_path}.mapping"
+      _proguard_mapping_path = "${_bundle_path}.mapping"
     }
 
     assert(_proguard_enabled || !defined(invoker.enable_multidex),
@@ -4520,11 +4506,6 @@
       _module_count = 0
       not_needed([ "_module_count" ])
 
-      # Define unique package for each async proguarding run.
-      _async_package_number = 1
-
-      not_needed([ "_async_package_number" ])
-
       foreach(_module, invoker.extra_modules) {
         _module_count += 1
         assert(defined(_module.name),
@@ -4542,68 +4523,23 @@
             "$_module_target_gen_dir/${_module_target_name}.build_config"
         _module.build_config_target =
             "$_module_target$build_config_target_suffix"
-
-        if (defined(_module.proguard_async) && _module.proguard_async) {
-          if (_proguard_enabled) {
-            # Use asynchronous proguarding for async modules.
-            _async_proguard_mapping_path =
-                "${_bundle_path}_${_module.name}.mapping"
-
-            _dex_zip = "${target_out_dir}/${target_name}/${target_name}_${_module.name}_dex.zip"
-            _module.dex_path = _dex_zip
-
-            # Give unique name to each async dex target using module name.
-            _async_dex_target = "${target_name}_${_module.name}_dex"
-
-            dex(_async_dex_target) {
-              enable_multidex = _enable_multidex
-              proguard_enabled = true
-              proguard_mapping_path = _async_proguard_mapping_path
-              forward_variables_from(invoker,
-                                     [
-                                       "proguard_jar_path",
-                                       "min_sdk_version",
-                                     ])
-              build_config = _module.build_config
-              repackage_classes = "ap${_async_package_number}"
-
-              # TODO(https://crbug.com/952858): R8 currently doesn't handle
-              # applying mapping files.
-              # Pass mapping file of synchronous proguarding run to async
-              # module proguarding runs to preserve compatibility.
-              # apply_mapping = _sync_proguard_mapping_path
-
-              deps = [
-                _module.module_target,
-                _sync_dex_target_dep,
-              ]
-
-              output = _dex_zip
-            }
-            _module.async_dex_target = _async_dex_target
-            _async_package_number += 1
-          }
-
-          _async_modules += [ _module ]
-        } else {
-          _sync_modules += [ _module ]
-        }
+        _modules += [ _module ]
       }
     }
 
     # Make build config, which is required for synchronized proguarding.
-    _sync_module_java_targets = []
-    _sync_module_build_configs = []
-    _sync_module_targets = []
-    foreach(_module, _sync_modules) {
-      _sync_module_targets += [ _module.module_target ]
-      _sync_module_java_targets += [ "${_module.module_target}__java" ]
-      _sync_module_build_configs += [ _module.build_config ]
+    _module_java_targets = []
+    _module_build_configs = []
+    _module_targets = []
+    foreach(_module, _modules) {
+      _module_targets += [ _module.module_target ]
+      _module_java_targets += [ "${_module.module_target}__java" ]
+      _module_build_configs += [ _module.build_config ]
     }
 
     # Used to expose the module Java targets of the bundle.
     group("${target_name}__java") {
-      deps = _sync_module_java_targets
+      deps = _module_java_targets
     }
     group("${target_name}__compile_resources") {
       deps = [
@@ -4628,14 +4564,11 @@
         "${target_gen_dir}/${target_name}/${target_name}__unsplit_dex.zip"
 
     write_build_config(_build_config_target) {
-      # We don't want async modules to be proguarded synchronously, so we leave
-      # them out of possible_config_deps.
       type = "android_app_bundle"
-      possible_config_deps =
-          _sync_module_targets + [ proguard_android_sdk_dep_ ]
+      possible_config_deps = _module_targets + [ proguard_android_sdk_dep_ ]
       build_config = _build_config
       proguard_enabled = _proguard_enabled
-      module_build_configs = _sync_module_build_configs
+      module_build_configs = _module_build_configs
       final_dex_path = _unsplit_dex_zip
 
       if (_proguard_enabled) {
@@ -4676,7 +4609,7 @@
             proguard_expectations_file = _proguard_expectations_file
           }
 
-          deps = _sync_module_java_targets + [ ":$_build_config_target" ]
+          deps = _module_java_targets + [ ":$_build_config_target" ]
           output = _unsplit_dex_zip
         }
       }
@@ -4684,30 +4617,25 @@
       _dexsplitter_target = "${target_name}__dexsplitter"
       dexsplitter(_dexsplitter_target) {
         input_dex_zip = _unsplit_dex_zip
-        proguard_mapping = _sync_proguard_mapping_path
-        all_modules = _sync_modules
+        proguard_mapping = _proguard_mapping_path
+        all_modules = _modules
         deps = [
                  ":$_build_config_target",
                  _sync_dex_target_dep,
-               ] + _sync_module_java_targets
+               ] + _module_java_targets
       }
     }
 
-    # Merge async and sync module scopes.
-    _all_modules = _sync_modules + _async_modules
-
     _all_create_module_targets = []
     _all_module_zip_paths = []
     _all_module_build_configs = []
-    foreach(_module, _all_modules) {
+    foreach(_module, _modules) {
       _module_target = _module.module_target
       _module_build_config = _module.build_config
       _module_build_config_target = _module.build_config_target
 
       if (!_proguard_enabled) {
         _dex_target_for_module = "${_module_target}__final_dex"
-      } else if (defined(_module.dex_path)) {
-        _dex_target_for_module = ":${_module.async_dex_target}"
       } else {
         _dex_target_for_module = ":$_dexsplitter_target"
       }
@@ -4724,12 +4652,6 @@
         build_config = _module_build_config
         module_zip_path = _module_zip_path
 
-        # If module is async, use defined dex_path directly rather than
-        # build config FileArg.
-        if (defined(_module.dex_path)) {
-          dex_path = _module.dex_path
-        }
-
         deps = [
           _dex_target_for_module,
           _module_build_config_target,
@@ -4818,7 +4740,7 @@
         ]
       }
 
-      foreach(_module, _all_modules) {
+      foreach(_module, _modules) {
         _rebased_build_config =
             rebase_path(_module.build_config, root_build_dir)
         args += [
@@ -4837,10 +4759,7 @@
     # (have proguard enabled).
     if (_proguard_enabled) {
       # Merge all module targets to obtain size info files for all targets.
-      _all_module_targets = _sync_module_targets
-      foreach(_async_module, _async_modules) {
-        _all_module_targets += [ _async_module.module_target ]
-      }
+      _all_module_targets = _module_targets
 
       _size_info_target = "${target_name}__size_info"
       create_size_info_files(_size_info_target) {
@@ -4911,14 +4830,13 @@
         ]
       }
 
-      # TODO(crbug.com/938635): Combine async module mapping paths with the sync one.
       if (_proguard_enabled) {
         args += [
           "--proguard-mapping-path",
-          rebase_path(_sync_proguard_mapping_path, root_build_dir),
+          rebase_path(_proguard_mapping_path, root_build_dir),
         ]
         data_deps += [ "//build/android/stacktrace:java_deobfuscate" ]
-        data += [ _sync_proguard_mapping_path ]
+        data += [ _proguard_mapping_path ]
       }
     }
 
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 60fbebc..09f4f8e 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -222,15 +222,6 @@
     # Reduce symbol level when it will cause invalid elf files to be created
     # (due to file size). https://crbug.com/648948.
     symbol_level = 1
-  } else if (is_win && use_goma && !is_clang) {
-    # goma doesn't support PDB files, so we disable symbols during goma
-    # compilation because otherwise the redundant debug information generated
-    # by visual studio (repeated in every .obj file) makes linker
-    # memory consumption and link times unsustainable (crbug.com/630074).
-    # Clang on windows does not have this issue.
-    # If you use is_win_fastlink = true or lld or clang then you can set
-    # symbol_level = 2 when using goma.
-    symbol_level = 1
   } else if (is_cros_chrome_sdk) {
     # Use lower symbol level in Simple Chrome build for faster link time.
     # For Simple Chrome, this should take precedence over is_official_build,
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 75c7271..bc9f364 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8900075814043677168
\ No newline at end of file
+8900019363308510144
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 3cb6c2e..3ae3f17 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8900078822768978496
\ No newline at end of file
+8900019543986013504
\ No newline at end of file
diff --git a/build/toolchain/goma.gni b/build/toolchain/goma.gni
index 2fbf572..ba54c4e 100644
--- a/build/toolchain/goma.gni
+++ b/build/toolchain/goma.gni
@@ -27,3 +27,6 @@
     }
   }
 }
+
+assert(!is_win || !use_goma || is_clang,
+       "cl.exe does not work on goma, use clang")
diff --git a/cc/input/scrollbar_controller.cc b/cc/input/scrollbar_controller.cc
index 4e56a4d..2f4221e 100644
--- a/cc/input/scrollbar_controller.cc
+++ b/cc/input/scrollbar_controller.cc
@@ -255,9 +255,15 @@
   float scaled_scroller_to_scrollbar_ratio = GetScrollerToScrollbarRatio();
   float current_scroll_position = currently_captured_scrollbar_->current_pos();
 
-  // Thumb position needs to be floored to match main thread per pixel behavior
-  float thumb_position = floorf(std::max(0.0f, current_scroll_position) /
-                                scaled_scroller_to_scrollbar_ratio);
+  // Thumb position needs to be floored and Values between 0 and 1 are rounded
+  // to one to match main thread per pixel behavior. Corresponding main thread
+  // code in ScrollbarTheme::ThumbPosition
+  float thumb_position = std::max(0.0f, current_scroll_position) /
+                         scaled_scroller_to_scrollbar_ratio;
+  thumb_position = (thumb_position < 1.0 && thumb_position > 0.0)
+                       ? 1.0
+                       : floorf(thumb_position);
+
   float delta_in_orientation = orientation == ScrollbarOrientation::VERTICAL
                                    ? pointer_delta.y()
                                    : pointer_delta.x();
diff --git a/cc/paint/paint_image.cc b/cc/paint/paint_image.cc
index 0331bfc1..c601c01 100644
--- a/cc/paint/paint_image.cc
+++ b/cc/paint/paint_image.cc
@@ -28,6 +28,13 @@
 const PaintImage::ContentId PaintImage::kInvalidContentId = -1;
 const PaintImage::GeneratorClientId PaintImage::kDefaultGeneratorClientId = 0;
 
+ImageHeaderMetadata::ImageHeaderMetadata() = default;
+ImageHeaderMetadata::ImageHeaderMetadata(const ImageHeaderMetadata& other) =
+    default;
+ImageHeaderMetadata& ImageHeaderMetadata::operator=(
+    const ImageHeaderMetadata& other) = default;
+ImageHeaderMetadata::ImageHeaderMetadata::~ImageHeaderMetadata() = default;
+
 PaintImage::PaintImage() = default;
 PaintImage::PaintImage(const PaintImage& other) = default;
 PaintImage::PaintImage(PaintImage&& other) = default;
@@ -153,13 +160,6 @@
   }
 }
 
-bool PaintImage::IsEligibleForAcceleratedDecoding() const {
-  if (!CanDecodeFromGenerator())
-    return false;
-  DCHECK(paint_image_generator_);
-  return paint_image_generator_->IsEligibleForAcceleratedDecoding();
-}
-
 SkISize PaintImage::GetSupportedDecodeSize(
     const SkISize& requested_size) const {
   // TODO(vmpstr): In some cases we do not support decoding to any other
@@ -292,10 +292,10 @@
              : GetSkImage()->height();
 }
 
-PaintImage::ImageType PaintImage::GetImageType() const {
+const ImageHeaderMetadata* PaintImage::GetImageHeaderMetadata() const {
   if (paint_image_generator_)
-    return paint_image_generator_->GetImageType();
-  return PaintImage::ImageType::kInvalid;
+    return paint_image_generator_->GetMetadataForDecodeAcceleration();
+  return nullptr;
 }
 
 bool PaintImage::IsYuv(SkYUVASizeInfo* yuva_size_info,
diff --git a/cc/paint/paint_image.h b/cc/paint/paint_image.h
index 0967fde..df01c10 100644
--- a/cc/paint/paint_image.h
+++ b/cc/paint/paint_image.h
@@ -10,6 +10,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
 #include "cc/paint/frame_metadata.h"
 #include "cc/paint/image_animation_count.h"
 #include "cc/paint/paint_export.h"
@@ -17,6 +18,7 @@
 #include "third_party/skia/include/core/SkYUVAIndex.h"
 #include "third_party/skia/include/core/SkYUVASizeInfo.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace cc {
 
@@ -25,6 +27,46 @@
 class PaintWorkletInput;
 using PaintRecord = PaintOpBuffer;
 
+enum class ImageType { kPNG, kJPEG, kWEBP, kGIF, kICO, kBMP, kInvalid };
+
+enum class YUVSubsampling { k410, k411, k420, k422, k440, k444, kUnknown };
+
+struct CC_PAINT_EXPORT ImageHeaderMetadata {
+ public:
+  ImageHeaderMetadata();
+  ImageHeaderMetadata(const ImageHeaderMetadata& other);
+  ImageHeaderMetadata& operator=(const ImageHeaderMetadata& other);
+  ~ImageHeaderMetadata();
+
+  // The image type, e.g., JPEG or WebP.
+  ImageType image_type = ImageType::kInvalid;
+
+  // The subsampling format used for the chroma planes, e.g., YUV 4:2:0.
+  YUVSubsampling yuv_subsampling = YUVSubsampling::kUnknown;
+
+  // The visible size of the image (i.e., the area that contains meaningful
+  // pixels).
+  gfx::Size image_size;
+
+  // The size of the area containing coded data, if known. For example, if the
+  // |image_size| for a 4:2:0 JPEG is 12x31, its coded size should be 16x32
+  // because the size of a minimum-coded unit for 4:2:0 is 16x16.
+  base::Optional<gfx::Size> coded_size;
+
+  // Whether the image embeds an ICC color profile.
+  bool has_embedded_color_profile = false;
+
+  // Whether all the data was received prior to starting decoding work.
+  bool all_data_received_prior_to_decode = false;
+
+  // For JPEGs only: whether the image is progressive (as opposed to baseline).
+  base::Optional<bool> jpeg_is_progressive;
+
+  // For WebPs only: whether this is a simple-format lossy image. See
+  // https://developers.google.com/speed/webp/docs/riff_container#simple_file_format_lossy.
+  base::Optional<bool> webp_is_non_extended_lossy;
+};
+
 // A representation of an image for the compositor.  This is the most abstract
 // form of images, and represents what is known at paint time.  Note that aside
 // from default construction, it can only be constructed using a
@@ -117,7 +159,6 @@
     // CheckerImageTracker for all heuristics used.
     kAsync
   };
-  enum class ImageType { kPNG, kJPEG, kWEBP, kGIF, kICO, kBMP, kInvalid };
 
   // Returns the more conservative mode out of the two given ones.
   static DecodingMode GetConservative(DecodingMode one, DecodingMode two);
@@ -141,18 +182,6 @@
   bool operator==(const PaintImage& other) const;
   bool operator!=(const PaintImage& other) const { return !(*this == other); }
 
-  // Returns true if the image is eligible for decoding using a hardware
-  // accelerator (which would require at least that all the encoded data has
-  // been received). Returns false otherwise or if the image cannot be decoded
-  // from a PaintImageGenerator. Notice that a return value of true does not
-  // guarantee that the hardware accelerator supports the image. It only
-  // indicates that the software decoder hasn't done any work with the image, so
-  // sending it to a hardware decoder is appropriate.
-  //
-  // TODO(andrescj): consider supporting the non-PaintImageGenerator path which
-  // is expected to be rare.
-  bool IsEligibleForAcceleratedDecoding() const;
-
   // Returns the smallest size that is at least as big as the requested_size
   // such that we can decode to exactly that scale. If the requested size is
   // larger than the image, this returns the image size. Any returned value is
@@ -227,6 +256,7 @@
   SkColorSpace* color_space() const {
     return paint_worklet_input_ ? nullptr : GetSkImage()->colorSpace();
   }
+  const gfx::Rect subset_rect() const { return subset_rect_; }
 
   // Returns whether this image will be decoded and rendered from YUV data
   // and fills out plane size info, plane index info, and the matrix for
@@ -239,8 +269,9 @@
   // Returns the color type of this image.
   SkColorType GetColorType() const;
 
-  // Returns the image type (e.g. PNG, WEBP) of this image.
-  ImageType GetImageType() const;
+  // Returns general information about the underlying image. Returns nullptr if
+  // there is no available |paint_image_generator_|.
+  const ImageHeaderMetadata* GetImageHeaderMetadata() const;
 
   // Returns a unique id for the pixel data for the frame at |frame_index|.
   FrameKey GetKeyForFrame(size_t frame_index) const;
diff --git a/cc/paint/paint_image_generator.cc b/cc/paint/paint_image_generator.cc
index 41483fa..740808e2 100644
--- a/cc/paint/paint_image_generator.cc
+++ b/cc/paint/paint_image_generator.cc
@@ -33,8 +33,9 @@
   return info_.dimensions();
 }
 
-PaintImage::ImageType PaintImageGenerator::GetImageType() const {
-  return PaintImage::ImageType::kInvalid;
+const ImageHeaderMetadata*
+PaintImageGenerator::GetMetadataForDecodeAcceleration() const {
+  return nullptr;
 }
 
 }  // namespace cc
diff --git a/cc/paint/paint_image_generator.h b/cc/paint/paint_image_generator.h
index 1ff7515..6481c7a 100644
--- a/cc/paint/paint_image_generator.h
+++ b/cc/paint/paint_image_generator.h
@@ -29,14 +29,6 @@
 
   PaintImageGenerator& operator=(const PaintImageGenerator&) = delete;
 
-  // Returns true if we can guarantee that the software decoder hasn't done work
-  // on the image, so it's appropriate to send the encoded image to a hardware
-  // accelerator. False if we can't guarantee this or if not applicable. For
-  // example, if the encoded data comes incrementally, and the software decoder
-  // starts working with partial data, the image shouldn't later be sent to a
-  // hardware decoder.
-  virtual bool IsEligibleForAcceleratedDecoding() const = 0;
-
   // Returns a reference to the encoded content of this image.
   virtual sk_sp<SkData> GetEncodedData() const = 0;
 
@@ -88,7 +80,9 @@
   const SkImageInfo& GetSkImageInfo() const { return info_; }
   const std::vector<FrameMetadata>& GetFrameMetadata() const { return frames_; }
 
-  virtual PaintImage::ImageType GetImageType() const;
+  // Returns the information required to decide whether or not hardware
+  // acceleration can be used to decode this image.
+  virtual const ImageHeaderMetadata* GetMetadataForDecodeAcceleration() const;
 
  protected:
   // |info| is the info for this paint image generator.
diff --git a/cc/test/fake_paint_image_generator.cc b/cc/test/fake_paint_image_generator.cc
index 29f1991..7e27e0985 100644
--- a/cc/test/fake_paint_image_generator.cc
+++ b/cc/test/fake_paint_image_generator.cc
@@ -36,10 +36,6 @@
 
 FakePaintImageGenerator::~FakePaintImageGenerator() = default;
 
-bool FakePaintImageGenerator::IsEligibleForAcceleratedDecoding() const {
-  return is_eligible_for_accelerated_decode_;
-}
-
 sk_sp<SkData> FakePaintImageGenerator::GetEncodedData() const {
   return SkData::MakeEmpty();
 }
@@ -113,8 +109,9 @@
   return PaintImageGenerator::GetSupportedDecodeSize(requested_size);
 }
 
-PaintImage::ImageType FakePaintImageGenerator::GetImageType() const {
-  return image_type_;
+const ImageHeaderMetadata*
+FakePaintImageGenerator::GetMetadataForDecodeAcceleration() const {
+  return &image_metadata_;
 }
 
 }  // namespace cc
diff --git a/cc/test/fake_paint_image_generator.h b/cc/test/fake_paint_image_generator.h
index 6a51836c..8bcdf56 100644
--- a/cc/test/fake_paint_image_generator.h
+++ b/cc/test/fake_paint_image_generator.h
@@ -33,7 +33,6 @@
   FakePaintImageGenerator& operator=(const FakePaintImageGenerator&) = delete;
 
   // PaintImageGenerator implementation.
-  bool IsEligibleForAcceleratedDecoding() const override;
   sk_sp<SkData> GetEncodedData() const override;
   bool GetPixels(const SkImageInfo& info,
                  void* pixels,
@@ -50,7 +49,7 @@
                       size_t frame_index,
                       uint32_t lazy_pixel_ref) override;
   SkISize GetSupportedDecodeSize(const SkISize& requested_size) const override;
-  PaintImage::ImageType GetImageType() const override;
+  const ImageHeaderMetadata* GetMetadataForDecodeAcceleration() const override;
 
   const base::flat_map<size_t, int>& frames_decoded() const {
     return frames_decoded_count_;
@@ -61,11 +60,8 @@
   }
   void reset_frames_decoded() { frames_decoded_count_.clear(); }
   void SetExpectFallbackToRGB() { expect_fallback_to_rgb_ = true; }
-  void SetEligibleForAcceleratedDecoding() {
-    is_eligible_for_accelerated_decode_ = true;
-  }
-  void SetImageType(PaintImage::ImageType image_type) {
-    image_type_ = image_type;
+  void SetImageHeaderMetadata(const ImageHeaderMetadata& image_metadata) {
+    image_metadata_ = image_metadata;
   }
 
  private:
@@ -73,7 +69,6 @@
   SkPixmap image_pixmap_;
   base::flat_map<size_t, int> frames_decoded_count_;
   std::vector<SkISize> supported_sizes_;
-  PaintImage::ImageType image_type_ = PaintImage::ImageType::kInvalid;
   std::vector<SkImageInfo> decode_infos_;
   bool is_yuv_ = false;
   SkYUVASizeInfo yuva_size_info_;
@@ -81,7 +76,7 @@
   // planes and after Chrome implements it, we should no longer expect RGB
   // fallback.
   bool expect_fallback_to_rgb_ = false;
-  bool is_eligible_for_accelerated_decode_ = false;
+  ImageHeaderMetadata image_metadata_;
 };
 
 }  // namespace cc
diff --git a/cc/test/skia_common.cc b/cc/test/skia_common.cc
index 6c940ab9..c47065e 100644
--- a/cc/test/skia_common.cc
+++ b/cc/test/skia_common.cc
@@ -148,7 +148,6 @@
         info, std::vector<FrameMetadata>{FrameMetadata()},
         allocate_encoded_data);
   }
-  generator->SetEligibleForAcceleratedDecoding();
   auto paint_image =
       PaintImageBuilder::WithDefault()
           .set_id(id)
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index d8750a1..dabb930 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -30,6 +30,7 @@
 #include "gpu/command_buffer/common/sync_token.h"
 #include "gpu/config/gpu_finch_features.h"
 #include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkData.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/core/SkYUVAIndex.h"
@@ -557,12 +558,15 @@
     TRACE_EVENT2("cc", "GpuImageDecodeTaskImpl::RunOnWorkerThread", "mode",
                  "gpu", "source_prepare_tiles_id",
                  tracing_info_.prepare_tiles_id);
+
+    const auto* image_metadata = image_.paint_image().GetImageHeaderMetadata();
+    const ImageType image_type =
+        image_metadata ? image_metadata->image_type : ImageType::kInvalid;
     devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
         &image_.paint_image(),
         devtools_instrumentation::ScopedImageDecodeTask::kGpu,
         ImageDecodeCache::ToScopedTaskType(tracing_info_.task_type),
-        ImageDecodeCache::ToScopedImageType(
-            image_.paint_image().GetImageType()));
+        ImageDecodeCache::ToScopedImageType(image_type));
     cache_->DecodeImageInTask(image_, tracing_info_.task_type);
   }
 
@@ -589,12 +593,10 @@
   ImageUploadTaskImpl(GpuImageDecodeCache* cache,
                       const DrawImage& draw_image,
                       scoped_refptr<TileTask> decode_dependency,
-                      sk_sp<SkData> encoded_data,
                       const ImageDecodeCache::TracingInfo& tracing_info)
       : TileTask(false),
         cache_(cache),
         image_(draw_image),
-        encoded_data_(std::move(encoded_data)),
         tracing_info_(tracing_info) {
     DCHECK(!SkipImage(draw_image));
     // If an image is already decoded and locked, we will not generate a
@@ -610,7 +612,7 @@
   void RunOnWorkerThread() override {
     TRACE_EVENT2("cc", "ImageUploadTaskImpl::RunOnWorkerThread", "mode", "gpu",
                  "source_prepare_tiles_id", tracing_info_.prepare_tiles_id);
-    cache_->UploadImageInTask(image_, std::move(encoded_data_));
+    cache_->UploadImageInTask(image_);
   }
 
   // Overridden from TileTask:
@@ -624,7 +626,6 @@
  private:
   GpuImageDecodeCache* cache_;
   DrawImage image_;
-  sk_sp<SkData> encoded_data_;
   const ImageDecodeCache::TracingInfo tracing_info_;
 };
 
@@ -1029,7 +1030,6 @@
   const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image);
   ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
   scoped_refptr<ImageData> new_data;
-  sk_sp<SkData> encoded_data;
   if (!image_data) {
     // We need an ImageData, create one now. Note that hardware decode
     // acceleration is allowed only in the DecodeTaskType::kPartOfUploadTask
@@ -1038,8 +1038,7 @@
     new_data = CreateImageData(
         draw_image,
         task_type ==
-            DecodeTaskType::kPartOfUploadTask /* allow_hardware_decode */,
-        &encoded_data);
+            DecodeTaskType::kPartOfUploadTask /* allow_hardware_decode */);
     image_data = new_data.get();
   } else if (image_data->decode.decode_failure) {
     // We have already tried and failed to decode this image, so just return.
@@ -1090,7 +1089,7 @@
     task = base::MakeRefCounted<ImageUploadTaskImpl>(
         this, draw_image,
         GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type),
-        std::move(encoded_data), tracing_info);
+        tracing_info);
     image_data->upload.task = task;
   } else {
     task = GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type);
@@ -1129,11 +1128,9 @@
   base::AutoLock lock(lock_);
   const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image);
   ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
-  sk_sp<SkData> encoded_data;
   if (!image_data) {
     // We didn't find the image, create a new entry.
-    auto data = CreateImageData(draw_image, true /* allow_hardware_decode */,
-                                &encoded_data);
+    auto data = CreateImageData(draw_image, true /* allow_hardware_decode */);
     image_data = data.get();
     AddToPersistentCache(draw_image, std::move(data));
   }
@@ -1148,7 +1145,7 @@
   // We may or may not need to decode and upload the image we've found, the
   // following functions early-out to if we already decoded.
   DecodeImageIfNecessary(draw_image, image_data, TaskType::kInRaster);
-  UploadImageIfNecessary(draw_image, image_data, std::move(encoded_data));
+  UploadImageIfNecessary(draw_image, image_data);
   // Unref the image decode, but not the image. The image ref will be released
   // in DrawWithImageFinished.
   UnrefImageDecode(draw_image, cache_key);
@@ -1472,8 +1469,7 @@
   DecodeImageIfNecessary(draw_image, image_data, task_type);
 }
 
-void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image,
-                                            sk_sp<SkData> encoded_data) {
+void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
                "GpuImageDecodeCache::UploadImage");
   base::Optional<viz::RasterContextProvider::ScopedRasterContextLock>
@@ -1493,7 +1489,7 @@
 
   if (image_data->is_bitmap_backed)
     DecodeImageIfNecessary(draw_image, image_data, TaskType::kInRaster);
-  UploadImageIfNecessary(draw_image, image_data, std::move(encoded_data));
+  UploadImageIfNecessary(draw_image, image_data);
 }
 
 void GpuImageDecodeCache::OnImageDecodeTaskCompleted(
@@ -1949,8 +1945,7 @@
 }
 
 void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
-                                                 ImageData* image_data,
-                                                 sk_sp<SkData> encoded_data) {
+                                                 ImageData* image_data) {
   CheckContextLockAcquiredIfNecessary();
   lock_.AssertAcquired();
 
@@ -2012,14 +2007,11 @@
       DCHECK_EQ(0, image_data->upload_scale_mip_level);
       const gfx::Size output_size(draw_image.paint_image().width(),
                                   draw_image.paint_image().height());
-      // Try to get the encoded data if we don't have it already: this can
-      // happen, e.g., if we create an upload task using a pre-existing
-      // ImageData. In that case, we previously decided to do hardware decode
-      // acceleration but we didn't cache the encoded data.
-      if (!encoded_data) {
-        encoded_data = draw_image.paint_image().GetSkImage()->refEncodedData();
-        DCHECK(encoded_data);
-      }
+
+      // Get the encoded data in a contiguous form.
+      sk_sp<SkData> encoded_data =
+          draw_image.paint_image().GetSkImage()->refEncodedData();
+      DCHECK(encoded_data);
       const uint32_t transfer_cache_id =
           ClientImageTransferCacheEntry::GetNextId();
       const gpu::SyncToken decode_sync_token =
@@ -2216,8 +2208,7 @@
 
 scoped_refptr<GpuImageDecodeCache::ImageData>
 GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image,
-                                     bool allow_hardware_decode,
-                                     sk_sp<SkData>* encoded_data) {
+                                     bool allow_hardware_decode) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
                "GpuImageDecodeCache::CreateImageData");
   lock_.AssertAcquired();
@@ -2263,21 +2254,12 @@
   // Figure out if we will do hardware accelerated decoding. The criteria is as
   // follows:
   //
-  // - Either the kVaapiJpegImageDecodeAcceleration or
-  //   kVaapiWebPImageDecodeAcceleration features are enabled.
   // - The caller allows hardware decodes.
   // - We are using the transfer cache (OOP-R).
   // - The image does not require downscaling for uploading (see TODO below).
-  // - All the encoded data was received prior to any decoding work. Otherwise,
-  //   it means that the software decoder has already started decoding the
-  //   image, so we just let it finish.
-  // - The image's color space is sRGB. This is because we don't currently
-  //   support detecting embedded color profiles.
+  // - The image does not require subsetting.
   // - The image is supported according to the profiles advertised by the GPU
-  //   service. Checking this involves obtaining the contiguous encoded data
-  //   which may require a copy if the data is not already contiguous. Because
-  //   of this, we return a pointer to the contiguous data (as |encoded_data|)
-  //   so that we can re-use it later (when requesting the image decode).
+  //   service.
   //
   // TODO(crbug.com/953367): currently, we don't support scaling with hardware
   // decode acceleration. Note that it's still okay for the image to be
@@ -2286,41 +2268,28 @@
   // TODO(crbug.com/981208): |data_size| needs to be set to the size of the
   // decoded data, but for accelerated decodes we won't know until the driver
   // gives us the result in the GPU process. Figure out what to do.
+  const ImageHeaderMetadata* image_metadata =
+      draw_image.paint_image().GetImageHeaderMetadata();
   bool do_hardware_accelerated_decode = false;
-  if ((allow_accelerated_jpeg_decodes_ || allow_accelerated_webp_decodes_) &&
-      allow_hardware_decode && upload_scale_mip_level == 0 &&
-      draw_image.paint_image().IsEligibleForAcceleratedDecoding() &&
-      draw_image.paint_image().color_space() &&
-      draw_image.paint_image().color_space()->isSRGB()) {
-    DCHECK_EQ(mode, DecodedDataMode::kTransferCache);
-    // TODO(crbug.com/995149): we should not require the encoded data to figure
-    // out if the hardware decoder supports the image. Instead, we should pass
-    // only the necessary attributes to CanDecodeWithHardwareAcceleration().
-    // This is important because extracting the encoded data may require a copy
-    // if the data is not contiguous.
-    sk_sp<SkData> tmp_encoded_data =
-        draw_image.paint_image().GetSkImage()
-            ? draw_image.paint_image().GetSkImage()->refEncodedData()
-            : nullptr;
-    if (tmp_encoded_data &&
-        context_->ContextSupport()->CanDecodeWithHardwareAcceleration(
-            base::make_span<const uint8_t>(tmp_encoded_data->bytes(),
-                                           tmp_encoded_data->size()))) {
-      const bool is_jpeg = (draw_image.paint_image().GetImageType() ==
-                            PaintImage::ImageType::kJPEG);
-      const bool is_webp = (draw_image.paint_image().GetImageType() ==
-                            PaintImage::ImageType::kWEBP);
-      do_hardware_accelerated_decode =
-          (is_jpeg && allow_accelerated_jpeg_decodes_) ||
-          (is_webp && allow_accelerated_webp_decodes_);
-      DCHECK(encoded_data);
-      *encoded_data = std::move(tmp_encoded_data);
-    }
+  if (allow_hardware_decode && mode == DecodedDataMode::kTransferCache &&
+      upload_scale_mip_level == 0 &&
+      draw_image.paint_image().subset_rect().IsEmpty() &&
+      context_->ContextSupport()->CanDecodeWithHardwareAcceleration(
+          image_metadata)) {
+    DCHECK(image_metadata);
+    DCHECK_EQ(image_metadata->image_size.width(),
+              draw_image.paint_image().width());
+    DCHECK_EQ(image_metadata->image_size.height(),
+              draw_image.paint_image().height());
+
+    const bool is_jpeg = (image_metadata->image_type == ImageType::kJPEG);
+    const bool is_webp = (image_metadata->image_type == ImageType::kWEBP);
+    do_hardware_accelerated_decode =
+        (is_jpeg && allow_accelerated_jpeg_decodes_) ||
+        (is_webp && allow_accelerated_webp_decodes_);
+    DCHECK(!do_hardware_accelerated_decode || !is_bitmap_backed);
   }
 
-  // If draw_image.paint_image().IsEligibleForAcceleratedDecoding() returns
-  // true, the image should not be backed by a bitmap.
-  DCHECK(!do_hardware_accelerated_decode || !is_bitmap_backed);
   SkYUVASizeInfo target_yuva_size_info;
   // We fill out a default value for |yuv_color_space| but only fill out the
   // base::Optional member in ImageData if it is YUV.
@@ -2678,8 +2647,8 @@
 
 size_t GpuImageDecodeCache::GetDrawImageSizeForTesting(const DrawImage& image) {
   base::AutoLock lock(lock_);
-  scoped_refptr<ImageData> data = CreateImageData(
-      image, false /* allow_hardware_decode */, nullptr /* encoded_data */);
+  scoped_refptr<ImageData> data =
+      CreateImageData(image, false /* allow_hardware_decode */);
   return data->size;
 }
 
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h
index 2f53534..fdfd114 100644
--- a/cc/tiles/gpu_image_decode_cache.h
+++ b/cc/tiles/gpu_image_decode_cache.h
@@ -19,7 +19,6 @@
 #include "cc/cc_export.h"
 #include "cc/paint/image_transfer_cache_entry.h"
 #include "cc/tiles/image_decode_cache.h"
-#include "third_party/skia/include/core/SkData.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkYUVAIndex.h"
 #include "third_party/skia/include/gpu/gl/GrGLTypes.h"
@@ -177,7 +176,7 @@
 
   // Called by Decode / Upload tasks.
   void DecodeImageInTask(const DrawImage& image, TaskType task_type);
-  void UploadImageInTask(const DrawImage& image, sk_sp<SkData> encoded_data);
+  void UploadImageInTask(const DrawImage& image);
 
   // Called by Decode / Upload tasks when tasks are finished.
   void OnImageDecodeTaskCompleted(const DrawImage& image,
@@ -611,8 +610,7 @@
 
   scoped_refptr<GpuImageDecodeCache::ImageData> CreateImageData(
       const DrawImage& image,
-      bool allow_hardware_decode,
-      sk_sp<SkData>* encoded_data);
+      bool allow_hardware_decode);
   void WillAddCacheEntry(const DrawImage& draw_image);
   SkImageInfo CreateImageInfoForDrawImage(const DrawImage& draw_image,
                                           int upload_scale_mip_level) const;
@@ -646,8 +644,7 @@
 
   // Requires that the |context_| lock be held when calling.
   void UploadImageIfNecessary(const DrawImage& draw_image,
-                              ImageData* image_data,
-                              sk_sp<SkData> encoded_data);
+                              ImageData* image_data);
 
   // Flush pending operations on context_->GrContext() for each element of
   // |yuv_images| and then clear the vector.
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index d60b3a3..329edf9 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -183,7 +183,7 @@
   }
 
   bool CanDecodeWithHardwareAcceleration(
-      base::span<const uint8_t> encoded_data) const override {
+      const ImageHeaderMetadata* image_metadata) const override {
     return advertise_accelerated_decoding_;
   }
 
@@ -2950,23 +2950,27 @@
     : public GpuImageDecodeCacheTest {
  public:
   PaintImage CreatePaintImageForDecodeAcceleration(
-      const gfx::Size& size,
-      sk_sp<SkColorSpace> color_space = nullptr,
-      bool is_eligible_for_accelerated_decoding = true,
-      PaintImage::ImageType image_type = PaintImage::ImageType::kJPEG) {
-    SkImageInfo info =
-        SkImageInfo::Make(size.width(), size.height(), color_type_,
-                          kPremul_SkAlphaType, color_space);
+      ImageType image_type = ImageType::kJPEG) {
+    // Create a valid image metadata for hardware acceleration.
+    ImageHeaderMetadata image_data{};
+    image_data.image_size = GetNormalImageSize();
+    image_data.image_type = image_type;
+    image_data.all_data_received_prior_to_decode = true;
+    image_data.has_embedded_color_profile = false;
+    image_data.jpeg_is_progressive = false;
+    image_data.webp_is_non_extended_lossy = true;
+
+    SkImageInfo info = SkImageInfo::Make(
+        image_data.image_size.width(), image_data.image_size.height(),
+        color_type_, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
     sk_sp<FakePaintImageGenerator> generator;
     if (do_yuv_decode_) {
-      generator =
-          sk_make_sp<FakePaintImageGenerator>(info, GetYUV420SizeInfo(size));
+      generator = sk_make_sp<FakePaintImageGenerator>(
+          info, GetYUV420SizeInfo(image_data.image_size));
     } else {
       generator = sk_make_sp<FakePaintImageGenerator>(info);
     }
-    if (is_eligible_for_accelerated_decoding)
-      generator->SetEligibleForAcceleratedDecoding();
-    generator->SetImageType(image_type);
+    generator->SetImageHeaderMetadata(image_data);
     PaintImage image = PaintImageBuilder::WithDefault()
                            .set_id(PaintImage::GetNextId())
                            .set_paint_image_generator(generator)
@@ -2983,12 +2987,9 @@
 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
        RequestAcceleratedDecodeSuccessfully) {
   auto cache = CreateCache();
-  const gfx::Size image_size = GetNormalImageSize();
-  const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
-  const gfx::ColorSpace target_color_space(*image_color_space);
+  const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
   ASSERT_TRUE(target_color_space.IsValid());
-  const PaintImage image =
-      CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+  const PaintImage image = CreatePaintImageForDecodeAcceleration();
   const SkFilterQuality quality = kHigh_SkFilterQuality;
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
@@ -3000,8 +3001,10 @@
 
   // Accelerated decodes should not produce decode tasks.
   ASSERT_TRUE(result.task->dependencies().empty());
+  ASSERT_TRUE(image.GetImageHeaderMetadata());
   EXPECT_CALL(*raster_implementation(),
-              DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _))
+              DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size,
+                                    _, gfx::ColorSpace(), _))
       .Times(1);
   TestTileTaskRunner::ProcessTask(result.task.get());
 
@@ -3018,12 +3021,9 @@
 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
        RequestAcceleratedDecodeSuccessfullyWithColorSpaceConversion) {
   auto cache = CreateCache();
-  const gfx::Size image_size = GetNormalImageSize();
-  const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
   const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50();
   ASSERT_TRUE(target_color_space.IsValid());
-  const PaintImage image =
-      CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+  const PaintImage image = CreatePaintImageForDecodeAcceleration();
   const SkFilterQuality quality = kHigh_SkFilterQuality;
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
@@ -3035,12 +3035,13 @@
 
   // Accelerated decodes should not produce decode tasks.
   ASSERT_TRUE(result.task->dependencies().empty());
+  ASSERT_TRUE(image.GetImageHeaderMetadata());
   EXPECT_CALL(*raster_implementation(),
-              DoScheduleImageDecode(image_size, _,
-                                    cache->SupportsColorSpaceConversion()
-                                        ? target_color_space
-                                        : gfx::ColorSpace(),
-                                    _))
+              DoScheduleImageDecode(
+                  image.GetImageHeaderMetadata()->image_size, _,
+                  cache->SupportsColorSpaceConversion() ? target_color_space
+                                                        : gfx::ColorSpace(),
+                  _))
       .Times(1);
   TestTileTaskRunner::ProcessTask(result.task.get());
 
@@ -3057,12 +3058,9 @@
 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
        AcceleratedDecodeRequestFails) {
   auto cache = CreateCache();
-  const gfx::Size image_size = GetNormalImageSize();
-  const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
   const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50();
   ASSERT_TRUE(target_color_space.IsValid());
-  const PaintImage image =
-      CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+  const PaintImage image = CreatePaintImageForDecodeAcceleration();
   const SkFilterQuality quality = kHigh_SkFilterQuality;
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
@@ -3075,12 +3073,13 @@
   // Accelerated decodes should not produce decode tasks.
   ASSERT_TRUE(result.task->dependencies().empty());
   raster_implementation()->SetAcceleratedDecodingFailed();
+  ASSERT_TRUE(image.GetImageHeaderMetadata());
   EXPECT_CALL(*raster_implementation(),
-              DoScheduleImageDecode(image_size, _,
-                                    cache->SupportsColorSpaceConversion()
-                                        ? target_color_space
-                                        : gfx::ColorSpace(),
-                                    _))
+              DoScheduleImageDecode(
+                  image.GetImageHeaderMetadata()->image_size, _,
+                  cache->SupportsColorSpaceConversion() ? target_color_space
+                                                        : gfx::ColorSpace(),
+                  _))
       .Times(1);
   TestTileTaskRunner::ProcessTask(result.task.get());
 
@@ -3097,12 +3096,9 @@
 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
        CannotRequestAcceleratedDecodeBecauseOfStandAloneDecode) {
   auto cache = CreateCache();
-  const gfx::Size image_size = GetNormalImageSize();
-  const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
-  const gfx::ColorSpace target_color_space(*image_color_space);
+  const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
   ASSERT_TRUE(target_color_space.IsValid());
-  const PaintImage image =
-      CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+  const PaintImage image = CreatePaintImageForDecodeAcceleration();
   const SkFilterQuality quality = kHigh_SkFilterQuality;
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)),
@@ -3121,12 +3117,9 @@
 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
        CannotRequestAcceleratedDecodeBecauseOfNonZeroUploadMipLevel) {
   auto cache = CreateCache();
-  const gfx::Size image_size = GetNormalImageSize();
-  const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
-  const gfx::ColorSpace target_color_space(*image_color_space);
+  const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
   ASSERT_TRUE(target_color_space.IsValid());
-  const PaintImage image =
-      CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+  const PaintImage image = CreatePaintImageForDecodeAcceleration();
   const SkFilterQuality quality = kHigh_SkFilterQuality;
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality, CreateMatrix(SkSize::Make(0.5f, 0.5f)),
@@ -3145,68 +3138,11 @@
 }
 
 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
-       CannotRequestAcceleratedDecodeBecauseOfIneligiblePaintImage) {
-  auto cache = CreateCache();
-  const gfx::Size image_size = GetNormalImageSize();
-  const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
-  const gfx::ColorSpace target_color_space(*image_color_space);
-  ASSERT_TRUE(target_color_space.IsValid());
-  const PaintImage image = CreatePaintImageForDecodeAcceleration(
-      image_size, image_color_space,
-      false /* is_eligible_for_accelerated_decoding */);
-  const SkFilterQuality quality = kHigh_SkFilterQuality;
-  DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
-                       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)),
-                       PaintImage::kDefaultFrameIndex, target_color_space);
-  ImageDecodeCache::TaskResult result =
-      cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
-  EXPECT_TRUE(result.need_unref);
-  ASSERT_TRUE(result.task);
-
-  // A non-accelerated normal decode should produce a decode dependency.
-  ASSERT_EQ(result.task->dependencies().size(), 1u);
-  ASSERT_TRUE(result.task->dependencies()[0]);
-  TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
-  TestTileTaskRunner::ProcessTask(result.task.get());
-  cache->UnrefImage(draw_image);
-}
-
-TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
-       CannotRequestAcceleratedDecodeBecauseOfNonSRGBColorSpace) {
-  auto cache = CreateCache();
-  const gfx::Size image_size = GetNormalImageSize();
-  const sk_sp<SkColorSpace> image_color_space =
-      SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB);
-  const gfx::ColorSpace target_color_space(*image_color_space);
-  ASSERT_TRUE(target_color_space.IsValid());
-  const PaintImage image =
-      CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
-  const SkFilterQuality quality = kHigh_SkFilterQuality;
-  DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
-                       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)),
-                       PaintImage::kDefaultFrameIndex, target_color_space);
-  ImageDecodeCache::TaskResult result =
-      cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
-  EXPECT_TRUE(result.need_unref);
-  ASSERT_TRUE(result.task);
-
-  // A non-accelerated normal decode should produce a decode dependency.
-  ASSERT_EQ(result.task->dependencies().size(), 1u);
-  ASSERT_TRUE(result.task->dependencies()[0]);
-  TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
-  TestTileTaskRunner::ProcessTask(result.task.get());
-  cache->UnrefImage(draw_image);
-}
-
-TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
        RequestAcceleratedDecodeSuccessfullyAfterCancellation) {
   auto cache = CreateCache();
-  const gfx::Size image_size = GetNormalImageSize();
-  const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB();
-  const gfx::ColorSpace target_color_space(*image_color_space);
+  const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
   ASSERT_TRUE(target_color_space.IsValid());
-  const PaintImage image =
-      CreatePaintImageForDecodeAcceleration(image_size, image_color_space);
+  const PaintImage image = CreatePaintImageForDecodeAcceleration();
   const SkFilterQuality quality = kHigh_SkFilterQuality;
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
@@ -3229,8 +3165,10 @@
   EXPECT_TRUE(another_result.need_unref);
   ASSERT_TRUE(another_result.task);
   EXPECT_EQ(another_result.task->dependencies().size(), 0u);
+  ASSERT_TRUE(image.GetImageHeaderMetadata());
   EXPECT_CALL(*raster_implementation(),
-              DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _))
+              DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size,
+                                    _, gfx::ColorSpace(), _))
       .Times(1);
   TestTileTaskRunner::ProcessTask(another_result.task.get());
 
@@ -3262,16 +3200,13 @@
 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
        RequestAcceleratedDecodeSuccessfully) {
   auto cache = CreateCache();
-  const gfx::Size image_size = GetNormalImageSize();
   const SkFilterQuality quality = kHigh_SkFilterQuality;
   const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
   ASSERT_TRUE(target_color_space.IsValid());
 
   // Try a JPEG image.
-  const PaintImage jpeg_image = CreatePaintImageForDecodeAcceleration(
-      image_size, SkColorSpace::MakeSRGB(),
-      true /* is_eligible_for_accelerated_decoding */,
-      PaintImage::ImageType::kJPEG);
+  const PaintImage jpeg_image =
+      CreatePaintImageForDecodeAcceleration(ImageType::kJPEG);
   DrawImage jpeg_draw_image(
       jpeg_image, SkIRect::MakeWH(jpeg_image.width(), jpeg_image.height()),
       quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
@@ -3289,8 +3224,11 @@
   // depends on a decode task that runs in the renderer.
   if (advertise_accelerated_decoding_ && allow_accelerated_jpeg_decoding_) {
     ASSERT_TRUE(jpeg_task.task->dependencies().empty());
-    EXPECT_CALL(*raster_implementation(),
-                DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _))
+    ASSERT_TRUE(jpeg_image.GetImageHeaderMetadata());
+    EXPECT_CALL(
+        *raster_implementation(),
+        DoScheduleImageDecode(jpeg_image.GetImageHeaderMetadata()->image_size,
+                              _, gfx::ColorSpace(), _))
         .Times(1);
   } else {
     ASSERT_EQ(jpeg_task.task->dependencies().size(), 1u);
@@ -3302,10 +3240,8 @@
   cache->UnrefImage(jpeg_draw_image);
 
   // Try a WebP image.
-  const PaintImage webp_image = CreatePaintImageForDecodeAcceleration(
-      image_size, SkColorSpace::MakeSRGB(),
-      true /* is_eligible_for_accelerated_decoding */,
-      PaintImage::ImageType::kWEBP);
+  const PaintImage webp_image =
+      CreatePaintImageForDecodeAcceleration(ImageType::kWEBP);
   DrawImage webp_draw_image(
       webp_image, SkIRect::MakeWH(webp_image.width(), webp_image.height()),
       quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
@@ -3316,8 +3252,11 @@
   ASSERT_TRUE(webp_task.task);
   if (advertise_accelerated_decoding_ && allow_accelerated_webp_decoding_) {
     ASSERT_TRUE(webp_task.task->dependencies().empty());
-    EXPECT_CALL(*raster_implementation(),
-                DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _))
+    ASSERT_TRUE(webp_image.GetImageHeaderMetadata());
+    EXPECT_CALL(
+        *raster_implementation(),
+        DoScheduleImageDecode(webp_image.GetImageHeaderMetadata()->image_size,
+                              _, gfx::ColorSpace(), _))
         .Times(1);
   } else {
     ASSERT_EQ(webp_task.task->dependencies().size(), 1u);
@@ -3329,10 +3268,8 @@
   cache->UnrefImage(webp_draw_image);
 
   // Try a PNG image (which should not be hardware accelerated).
-  const PaintImage png_image = CreatePaintImageForDecodeAcceleration(
-      image_size, SkColorSpace::MakeSRGB(),
-      true /* is_eligible_for_accelerated_decoding */,
-      PaintImage::ImageType::kPNG);
+  const PaintImage png_image =
+      CreatePaintImageForDecodeAcceleration(ImageType::kPNG);
   DrawImage png_draw_image(
       png_image, SkIRect::MakeWH(jpeg_image.width(), jpeg_image.height()),
       quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
diff --git a/cc/tiles/image_decode_cache.h b/cc/tiles/image_decode_cache.h
index 54b1316..f2451ca 100644
--- a/cc/tiles/image_decode_cache.h
+++ b/cc/tiles/image_decode_cache.h
@@ -74,12 +74,12 @@
   }
 
   static devtools_instrumentation::ScopedImageDecodeTask::ImageType
-  ToScopedImageType(PaintImage::ImageType image_type) {
+  ToScopedImageType(ImageType image_type) {
     using ScopedImageType =
         devtools_instrumentation::ScopedImageDecodeTask::ImageType;
-    if (image_type == PaintImage::ImageType::kWEBP)
+    if (image_type == ImageType::kWEBP)
       return ScopedImageType::kWebP;
-    if (image_type == PaintImage::ImageType::kJPEG)
+    if (image_type == ImageType::kJPEG)
       return ScopedImageType::kJpeg;
     return ScopedImageType::kOther;
   }
diff --git a/cc/tiles/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc
index 9a2a8e9..cbe8511 100644
--- a/cc/tiles/software_image_decode_cache.cc
+++ b/cc/tiles/software_image_decode_cache.cc
@@ -72,11 +72,15 @@
     TRACE_EVENT2("cc", "SoftwareImageDecodeTaskImpl::RunOnWorkerThread", "mode",
                  "software", "source_prepare_tiles_id",
                  tracing_info_.prepare_tiles_id);
+
+    const auto* image_metadata = paint_image_.GetImageHeaderMetadata();
+    const ImageType image_type =
+        image_metadata ? image_metadata->image_type : ImageType::kInvalid;
     devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
         paint_image_.GetSkImage().get(),
         devtools_instrumentation::ScopedImageDecodeTask::kSoftware,
         ImageDecodeCache::ToScopedTaskType(tracing_info_.task_type),
-        ImageDecodeCache::ToScopedImageType(paint_image_.GetImageType()));
+        ImageDecodeCache::ToScopedImageType(image_type));
     SoftwareImageDecodeCache::TaskProcessingResult result =
         cache_->DecodeImageInTask(image_key_, paint_image_, task_type_);
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 593ba50..7189e15 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=79
 MINOR=0
-BUILD=3938
+BUILD=3939
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 9c02bd36..05e38a9 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -475,23 +475,6 @@
     "//components/module_installer/android:module_interface_processor",
   ]
 
-  proguard_configs = []
-  if (async_ar) {
-    proguard_configs += [ "//chrome/android/features/ar/proguard_async.flags" ]
-  }
-  if (async_vr) {
-    proguard_configs += [
-      "//chrome/android/features/vr/proguard_async.flags",
-      "//chrome/android/features/vr/proguard_async_manual.flags",
-    ]
-  }
-  if (async_tab_ui) {
-    proguard_configs += [
-      "//chrome/android/features/tab_ui/proguard_async.flags",
-      "//chrome/android/features/tab_ui/proguard_async_manual.flags",
-    ]
-  }
-
   processor_args_javac = [ "dagger.fastInit=enabled" ]
 }
 
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index b21f8858..b44570f 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -5,8 +5,6 @@
 chrome_java_sources = [
   "java/src/com/google/android/apps/chrome/appwidget/bookmarks/BookmarkThumbnailWidgetProvider.java",
   "java/src/org/chromium/chrome/browser/ActivityTabProvider.java",
-  "java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java",
-  "java/src/org/chromium/chrome/browser/ActivityTaskDescriptionIconGenerator.java",
   "java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java",
   "java/src/org/chromium/chrome/browser/AppHooks.java",
   "java/src/org/chromium/chrome/browser/AppHooksModule.java",
@@ -393,6 +391,8 @@
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java",
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabSessionHandler.java",
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicy.java",
+  "java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java",
+  "java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionIconGenerator.java",
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java",
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabsClientFileProcessor.java",
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java",
@@ -831,7 +831,6 @@
   "java/src/org/chromium/chrome/browser/init/ChromeLifetimeController.java",
   "java/src/org/chromium/chrome/browser/init/EmptyBrowserParts.java",
   "java/src/org/chromium/chrome/browser/init/FirstDrawDetector.java",
-  "java/src/org/chromium/chrome/browser/init/InvalidStartupDialog.java",
   "java/src/org/chromium/chrome/browser/init/NativeInitializationController.java",
   "java/src/org/chromium/chrome/browser/init/NativeStartupBridge.java",
   "java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java",
diff --git a/chrome/android/features/ar/ar_module.gni b/chrome/android/features/ar/ar_module.gni
index 59e5c211..65266de9 100644
--- a/chrome/android/features/ar/ar_module.gni
+++ b/chrome/android/features/ar/ar_module.gni
@@ -19,5 +19,4 @@
   android_manifest = "//chrome/android/features/ar/AndroidManifest.xml"
   loadable_modules_32_bit = [ "$_libarcore_dir/armeabi-v7a/libarcore_sdk_c.so" ]
   loadable_modules_64_bit = [ "$_libarcore_dir/arm64-v8a/libarcore_sdk_c.so" ]
-  proguard_async = async_ar
 }
diff --git a/chrome/android/features/ar/proguard_async.flags b/chrome/android/features/ar/proguard_async.flags
deleted file mode 100644
index 282db1e1..0000000
--- a/chrome/android/features/ar/proguard_async.flags
+++ /dev/null
@@ -1,7 +0,0 @@
-# Explicitly keep the ArCoreShim interface. Because ArCoreShim
-# is in base, and its implementing class ArCoreShimImpl is in AR,
-# asynchronous proguarding of AR will cause ArCoreShim to be removed
-# during synchronous proguarding, which causes AR on Chrome to crash.
--keep interface org.chromium.chrome.browser.vr.ArCoreShim {
-  *;
-}
\ No newline at end of file
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index 750d2b4..8d8489f 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -175,8 +175,4 @@
     "//third_party/android_deps:com_android_support_support_v13_java",
     "//ui/android:ui_java",
   ]
-
-  if (async_tab_ui) {
-    proguard_configs = [ "//base/android/proguard/chromium_code.flags" ]
-  }
 }
diff --git a/chrome/android/features/tab_ui/buildflags.gni b/chrome/android/features/tab_ui/buildflags.gni
index 0637699..e15c9ae3e 100644
--- a/chrome/android/features/tab_ui/buildflags.gni
+++ b/chrome/android/features/tab_ui/buildflags.gni
@@ -5,7 +5,4 @@
 declare_args() {
   # Controls the feature being a DFM or not.
   disable_tab_ui_dfm = true
-
-  # Whether to create tab_ui module as an asynchronous DFM.
-  async_tab_ui = false
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java
index 230fe6f..9054166 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java
@@ -58,7 +58,7 @@
         }
         if (sRoundedChromeDrawable == null) {
             Bitmap chromeBitmap =
-                    BitmapFactory.decodeResource(context.getResources(), R.drawable.chromelogo16);
+                    BitmapFactory.decodeResource(mContext.getResources(), R.drawable.chromelogo16);
             sRoundedChromeDrawable = processBitmap(chromeBitmap);
         }
         mDefaultIconColor = mContext.getResources().getColor(R.color.default_icon_color);
@@ -66,7 +66,7 @@
     }
 
     private Drawable processBitmap(Bitmap bitmap) {
-        return FaviconUtils.createRoundedBitmapDrawable(
+        return FaviconUtils.createRoundedBitmapDrawable(mContext.getResources(),
                 Bitmap.createScaledBitmap(bitmap, mFaviconSize, mFaviconSize, true));
     }
 
diff --git a/chrome/android/features/tab_ui/proguard_async.flags b/chrome/android/features/tab_ui/proguard_async.flags
deleted file mode 100644
index a5c42ce..0000000
--- a/chrome/android/features/tab_ui/proguard_async.flags
+++ /dev/null
@@ -1,1034 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
--keep class android.content.res.Resources$Theme { *; }
-
--keep class android.support.v7.widget.GridLayoutManager { *; }
-
--keep class android.support.v7.widget.LinearLayoutManager { *; }
-
--keep class android.support.v7.widget.RecyclerView { *; }
-
--keep class android.support.v7.widget.RecyclerView$Adapter { *; }
-
--keep class android.support.v7.widget.RecyclerView$LayoutManager { *; }
-
--keep class android.support.v7.widget.RecyclerView$ViewHolder { *; }
-
--keep class android.support.v7.widget.helper.ItemTouchHelper { *; }
-
--keep class android.support.v7.widget.helper.ItemTouchHelper$Callback { *; }
-
--keep class android.support.v7.widget.helper.ItemTouchHelper$SimpleCallback { *; }
-
--keep class android.view.View$OnClickListener { *; }
-
--keep class android.widget.PopupWindow$OnDismissListener { *; }
-
--keep class boolean { *; }
-
--keep class float { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$anim { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$animator { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$array { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$attr { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$bool { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$color { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$dimen { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$drawable { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$font { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$fraction { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$id { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$integer { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$layout { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$menu { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$mipmap { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$plurals { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$string { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$style { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$styleable { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$transition { *; }
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R$xml { *; }
-
--keep class gen._chrome._android._monochrome_public_bundle__tab_ui_bundle_module__compile_resources.srcjar.R$dimen { *; }
-
--keep class gen._chrome._android._monochrome_public_bundle__tab_ui_bundle_module__compile_resources.srcjar.R$drawable { *; }
-
--keep class gen._chrome._android._monochrome_public_bundle__tab_ui_bundle_module__compile_resources.srcjar.R$id { *; }
-
--keep class gen._chrome._android._monochrome_public_bundle__tab_ui_bundle_module__compile_resources.srcjar.R$layout { *; }
-
--keep class int { *; }
-
--keep class int[] { *; }
-
--keep class long { *; }
-
--keep class null { *; }
-
--keep class org.apache.http.conn.scheme.LayeredSocketFactory { *; }
-
--keep class org.apache.http.conn.scheme.SocketFactory { *; }
-
--keep class org.apache.http.conn.ssl.AbstractVerifier { *; }
-
--keep class org.apache.http.conn.ssl.X509HostnameVerifier { *; }
-
--keep class org.apache.http.params.CoreConnectionPNames { *; }
-
--keep class org.chromium.base.Callback { *; }
-
--keep class org.chromium.base.ObserverList { *; }
-
--keep class org.chromium.base.Supplier { *; }
-
--keep class org.chromium.base.task.TaskTraits { *; }
-
--keep class org.chromium.chrome.browser.ThemeColorProvider { *; }
-
--keep class org.chromium.chrome.browser.ThemeColorProvider$ThemeColorObserver { *; }
-
--keep class org.chromium.chrome.browser.ThemeColorProvider$TintObserver { *; }
-
--keep class org.chromium.chrome.browser.compositor.CompositorViewHolder { *; }
-
--keep class org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver { *; }
-
--keep class org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior { *; }
-
--keep class org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior$OverviewModeObserver { *; }
-
--keep class org.chromium.chrome.browser.compositor.layouts.content.TabContentManager { *; }
-
--keep class org.chromium.chrome.browser.favicon.FaviconHelper { *; }
-
--keep class org.chromium.chrome.browser.favicon.FaviconHelper$FaviconImageCallback { *; }
-
--keep class org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager { *; }
-
--keep class org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager$FullscreenListener { *; }
-
--keep class org.chromium.chrome.browser.gesturenav.HistoryNavigationDelegate { *; }
-
--keep class org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher { *; }
-
--keep class org.chromium.chrome.browser.lifecycle.Destroyable { *; }
-
--keep class org.chromium.chrome.browser.lifecycle.LifecycleObserver { *; }
-
--keep class org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver { *; }
-
--keep class org.chromium.chrome.browser.profiles.Profile { *; }
-
--keep class org.chromium.chrome.browser.tab.EmptyTabObserver { *; }
-
--keep class org.chromium.chrome.browser.tab.Tab { *; }
-
--keep class org.chromium.chrome.browser.tab.TabObserver { *; }
-
--keep class org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver { *; }
-
--keep class org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver { *; }
-
--keep class org.chromium.chrome.browser.tabmodel.TabCreatorManager { *; }
-
--keep class org.chromium.chrome.browser.tabmodel.TabList { *; }
-
--keep class org.chromium.chrome.browser.tabmodel.TabModel { *; }
-
--keep class org.chromium.chrome.browser.tabmodel.TabModelObserver { *; }
-
--keep class org.chromium.chrome.browser.tabmodel.TabModelSelector { *; }
-
--keep class org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver { *; }
-
--keep class org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_groups.TabGroupUtils$1 { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcher { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcher$GridController { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator$ResetHandler { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator$ResetHandler { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridSheetMediator$ResetHandler { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridSheetViewBinder$ViewHolder { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGroupUi { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator$ResetHandler { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListMediator$CreateGroupButtonProvider { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListMediator$GridCardOnClickListenerProvider { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListMediator$IphProvider { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListMediator$TabActionListener { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListMediator$ThumbnailProvider { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListMediator$TitleProvider { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView$VisibilityListener { *; }
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabManagementDelegate { *; }
-
--keep class org.chromium.chrome.browser.toolbar.ToolbarManager { *; }
-
--keep class org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator$BottomControlsVisibilityController { *; }
-
--keep class org.chromium.chrome.browser.widget.ScrimView { *; }
-
--keep class org.chromium.chrome.browser.widget.ScrimView$ScrimObserver { *; }
-
--keep class org.chromium.chrome.browser.widget.ScrimView$ScrimParams { *; }
-
--keep class org.chromium.chrome.browser.widget.ScrimView$StatusBarScrimDelegate { *; }
-
--keep class org.chromium.chrome.browser.widget.bottomsheet.BottomSheet$BottomSheetContent { *; }
-
--keep class org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController { *; }
-
--keep class org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver { *; }
-
--keep class org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver { *; }
-
--keep class org.chromium.chrome.browser.widget.textbubble.TextBubble { *; }
-
--keep class org.chromium.components.feature_engagement.Tracker { *; }
-
--keep class org.chromium.content_public.browser.LoadUrlParams { *; }
-
--keep class org.chromium.ui.modelutil.ListModelBase { *; }
-
--keep class org.chromium.ui.modelutil.PropertyKey { *; }
-
--keep class org.chromium.ui.modelutil.PropertyKey[] { *; }
-
--keep class org.chromium.ui.modelutil.PropertyListModel { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModel { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModel$Builder { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModel$ReadableBooleanPropertyKey { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModel$ReadableFloatPropertyKey { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModel$ReadableIntPropertyKey { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModel$ReadableObjectPropertyKey { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModel$WritableBooleanPropertyKey { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModel$WritableFloatPropertyKey { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModel$WritableIntPropertyKey { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey { *; }
-
--keep class org.chromium.ui.modelutil.PropertyModelChangeProcessor$ViewBinder { *; }
-
--keep class org.chromium.ui.modelutil.PropertyObservable { *; }
-
--keep class org.chromium.ui.modelutil.RecyclerViewAdapter { *; }
-
--keep class org.chromium.ui.modelutil.RecyclerViewAdapter$Delegate { *; }
-
--keep class org.chromium.ui.modelutil.RecyclerViewAdapter$ViewHolderFactory { *; }
-
--keep class org.chromium.ui.modelutil.SimpleRecyclerViewMcpBase { *; }
-
--keep class org.chromium.ui.modelutil.SimpleRecyclerViewMcpBase$ItemViewTypeCallback { *; }
-
--keep class org.chromium.ui.modelutil.SimpleRecyclerViewMcpBase$ViewBinder { *; }
-
--keep class org.chromium.ui.resources.dynamics.DynamicResource { *; }
-
--keep class org.chromium.ui.resources.dynamics.DynamicResourceLoader { *; }
-
--keep class org.chromium.ui.resources.dynamics.ViewResourceAdapter { *; }
-
--keep class org.chromium.ui.widget.RectProvider { *; }
-
--keep class org.chromium.ui.widget.ViewRectProvider { *; }
-
--keep class android.support.v4.content.ContextCompat {
-  int getColor(android.content.Context, int);
-}
-
--keep class android.support.v4.content.res.ResourcesCompat {
-  android.graphics.drawable.Drawable getDrawable(android.content.res.Resources, int, android.content.res.Resources$Theme);
-}
-
--keep class android.support.v7.content.res.AppCompatResources {
-  android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
-}
-
--keep class android.support.v7.widget.RecyclerView$ItemAnimator {
-  void setAddDuration(long);
-  long getAddDuration();
-}
-
--keep class gen._chrome._android._features._tab_ui._java_resources.srcjar.R {
-  void onResourcesLoaded(int);
-  void onResourcesLoadedString(int);
-  void onResourcesLoadedDrawable(int);
-  void onResourcesLoadedMipmap(int);
-  void onResourcesLoadedStyleable(int);
-  void onResourcesLoadedInteger(int);
-  void onResourcesLoadedColor(int);
-  boolean sResourcesDidLoad;
-  void onResourcesLoadedMenu(int);
-  void onResourcesLoadedDimen(int);
-  void onResourcesLoadedXml(int);
-  void onResourcesLoadedLayout(int);
-  void onResourcesLoadedTransition(int);
-  void onResourcesLoadedBool(int);
-  void onResourcesLoadedFont(int);
-  void onResourcesLoadedAnim(int);
-  void onResourcesLoadedAnimator(int);
-  void onResourcesLoadedArray(int);
-  void onResourcesLoadedStyle(int);
-  void onResourcesLoadedFraction(int);
-  void onResourcesLoadedAttr(int);
-  void onResourcesLoadedId(int);
-  void onResourcesLoadedPlurals(int);
-}
-
--keep class org.apache.http.conn.ssl.SSLSocketFactory {
-  org.apache.http.conn.ssl.X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER;
-  org.apache.http.conn.ssl.X509HostnameVerifier STRICT_HOSTNAME_VERIFIER;
-  org.apache.http.conn.ssl.X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
-}
-
--keep class org.chromium.base.ApiCompatibilityUtils {
-  void setImageTintList(android.widget.ImageView, android.content.res.ColorStateList);
-  int getColor(android.content.res.Resources, int);
-}
-
--keep class org.chromium.base.ApplicationStatus {
-  android.app.Activity getLastTrackedFocusedActivity();
-}
-
--keep class org.chromium.base.ContextUtils {
-  android.content.Context getApplicationContext();
-}
-
--keep class org.chromium.base.Log {
-  void w(java.lang.String, java.lang.String, java.lang.Object[]);
-}
-
--keep class org.chromium.base.metrics.RecordHistogram {
-  void recordSparseHistogram(java.lang.String, int);
-  void recordCountHistogram(java.lang.String, int);
-}
-
--keep class org.chromium.base.metrics.RecordUserAction {
-  void record(java.lang.String);
-}
-
--keep class org.chromium.base.task.PostTask {
-  void postTask(org.chromium.base.task.TaskTraits, java.lang.Runnable);
-}
-
--keep class org.chromium.chrome.R$color {
-  int modern_grey_100;
-  int modern_grey_800_alpha_38;
-  int modern_primary_color;
-  int default_text_color_dark;
-  int modern_grey_300;
-}
-
--keep class org.chromium.chrome.R$dimen {
-  int toolbar_height_no_shadow;
-  int control_container_height;
-  int compositor_tab_title_text_size;
-  int default_favicon_size;
-}
-
--keep class org.chromium.chrome.R$drawable {
-  int btn_close;
-  int ic_globe_24dp;
-  int chromelogo16;
-}
-
--keep class org.chromium.chrome.R$plurals {
-  int bottom_tab_grid_title_placeholder;
-}
-
--keep class org.chromium.chrome.R$string {
-  int iph_tab_groups_your_tabs_together_text;
-  int bottom_tab_grid_opened_full;
-  int accessibility_tabstrip_tab;
-  int iph_tab_groups_quickly_compare_pages_text;
-  int iph_tab_groups_tap_to_see_another_tab_text;
-  int bottom_tab_grid_opened_half;
-  int iph_tab_groups_tap_to_see_another_tab_accessibility_text;
-  int accessibility_tabstrip_btn_close_tab;
-  int bottom_tab_grid_description;
-  int bottom_tab_grid_closed;
-}
-
--keep class org.chromium.chrome.browser.ChromeActivity {
-  org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher getLifecycleDispatcher();
-  org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior getOverviewModeBehavior();
-  org.chromium.chrome.browser.toolbar.ToolbarManager getToolbarManager();
-  void onBackPressed();
-  org.chromium.chrome.browser.compositor.layouts.content.TabContentManager getTabContentManager();
-  org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager getFullscreenManager();
-  boolean isWarmOnResume();
-  org.chromium.chrome.browser.tabmodel.TabModelSelector getTabModelSelector();
-  org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController getBottomSheetController();
-  org.chromium.chrome.browser.compositor.CompositorViewHolder getCompositorViewHolder();
-}
-
--keep class org.chromium.chrome.browser.ChromeFeatureList {
-  boolean isInitialized();
-  boolean isEnabled(java.lang.String);
-}
-
--keep class org.chromium.chrome.browser.ChromeTabbedActivity {
-  org.chromium.chrome.browser.tabmodel.TabModelSelector getTabModelSelector();
-  org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior getOverviewModeBehavior();
-}
-
--keep class org.chromium.chrome.browser.feature_engagement.TrackerFactory {
-  org.chromium.components.feature_engagement.Tracker getTrackerForProfile(org.chromium.chrome.browser.profiles.Profile);
-}
-
--keep class org.chromium.chrome.browser.gesturenav.HistoryNavigationLayout {
-  void setNavigationDelegate(org.chromium.chrome.browser.gesturenav.HistoryNavigationDelegate);
-}
-
--keep class org.chromium.chrome.browser.metrics.UmaSessionStats {
-  void registerSyntheticFieldTrial(java.lang.String, java.lang.String);
-}
-
--keep class org.chromium.chrome.browser.native_page.NativePageFactory {
-  boolean isNativePageUrl(java.lang.String, boolean);
-}
-
--keep class org.chromium.chrome.browser.tabmodel.TabCreatorManager$TabCreator {
-  org.chromium.chrome.browser.tab.Tab createNewTab(org.chromium.content_public.browser.LoadUrlParams, int, org.chromium.chrome.browser.tab.Tab);
-}
-
--keep class org.chromium.chrome.browser.tabmodel.TabModelFilter {
-  int index();
-  int indexOf(org.chromium.chrome.browser.tab.Tab);
-  boolean isIncognito();
-  java.util.List getRelatedTabList(int);
-}
-
--keep class org.chromium.chrome.browser.tabmodel.TabModelFilterProvider {
-  void removeTabModelFilterObserver(org.chromium.chrome.browser.tabmodel.TabModelObserver);
-  org.chromium.chrome.browser.tabmodel.TabModelFilter getTabModelFilter(boolean);
-  org.chromium.chrome.browser.tabmodel.TabModelFilter getCurrentTabModelFilter();
-  void addTabModelFilterObserver(org.chromium.chrome.browser.tabmodel.TabModelObserver);
-}
-
--keep class org.chromium.chrome.browser.tabmodel.TabModelUtils {
-  int getTabIndexById(org.chromium.chrome.browser.tabmodel.TabList, int);
-  org.chromium.chrome.browser.tab.Tab getTabById(org.chromium.chrome.browser.tabmodel.TabList, int);
-}
-
--keep class org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil {
-  boolean shouldShowOmniboxOnTabSwitcher();
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_groups.TabGroupUtils {
-  boolean isMoveInSameGroup(org.chromium.chrome.browser.tabmodel.TabModel, int, int);
-  boolean $assertionsDisabled;
-  void lambda$maybeShowIPH$0(org.chromium.components.feature_engagement.Tracker, java.lang.String);
-  void startObservingForTabGroupsIPH(org.chromium.chrome.browser.tabmodel.TabModelSelector);
-  void maybeShowIPH(java.lang.String, android.view.View);
-  org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver access$000();
-  int getLastTabModelIndexForList(org.chromium.chrome.browser.tabmodel.TabModelSelector, java.util.List);
-  org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver sTabModelSelectorTabObserver;
-  int getFirstTabModelIndexForList(org.chromium.chrome.browser.tabmodel.TabModelSelector, java.util.List);
-  org.chromium.chrome.browser.tab.Tab getSelectedTabInGroupForTab(org.chromium.chrome.browser.tabmodel.TabModelSelector, org.chromium.chrome.browser.tab.Tab);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherCoordinator {
-  org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator mTabGridCoordinator;
-  java.lang.String lambda$new$0(org.chromium.chrome.browser.tabmodel.TabModelSelector, android.content.Context, org.chromium.chrome.browser.tab.Tab);
-  org.chromium.ui.modelutil.PropertyModelChangeProcessor mContainerViewChangeProcessor;
-  org.chromium.chrome.browser.tasks.tab_management.TabGridDialogCoordinator mTabGridDialogCoordinator;
-  org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher mLifecycleDispatcher;
-  org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator mMediator;
-  org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider mMultiThumbnailCardProvider;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator {
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$TabActionListener getGridCardOnClickListener(org.chromium.chrome.browser.tab.Tab);
-  java.util.List getRelatedTabs(int);
-  org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator$ResetHandler access$300(org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator);
-  boolean mShouldIgnoreNextSelect;
-  org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager$FullscreenListener mFullscreenListener;
-  void lambda$getCreateGroupButtonOnClickListener$1(int);
-  org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator$ResetHandler mTabGridDialogResetHandler;
-  org.chromium.chrome.browser.tabmodel.TabModelSelector mTabModelSelector;
-  void prepareOverview();
-  org.chromium.chrome.browser.tabmodel.TabModelObserver mTabModelObserver;
-  boolean ableToCreateGroup(org.chromium.chrome.browser.tab.Tab);
-  void setContentOverlayVisibility(boolean);
-  org.chromium.ui.modelutil.PropertyModel access$000(org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator);
-  org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager mFullscreenManager;
-  boolean access$102(org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator, boolean);
-  org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator$ResetHandler mResetHandler;
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$TabActionListener getCreateGroupButtonOnClickListener(org.chromium.chrome.browser.tab.Tab);
-  void destroy();
-  org.chromium.base.ObserverList mObservers;
-  boolean access$100(org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator);
-  void setVisibility(boolean);
-  boolean ableToOpenDialog(org.chromium.chrome.browser.tab.Tab);
-  org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver mTabModelSelectorObserver;
-  void access$400(org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator, boolean);
-  void lambda$getGridCardOnClickListener$0(int);
-  org.chromium.ui.modelutil.PropertyModel mContainerViewModel;
-  org.chromium.chrome.browser.compositor.CompositorViewHolder mCompositorViewHolder;
-  org.chromium.chrome.browser.tabmodel.TabModelSelector access$200(org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider {
-  android.graphics.Paint access$1000(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  org.chromium.chrome.browser.tasks.tab_management.TabListFaviconProvider access$1200(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  org.chromium.chrome.browser.tasks.tab_management.TabListFaviconProvider mTabListFaviconProvider;
-  java.util.List mThumbnailRects;
-  float access$900(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  android.graphics.Paint mTextPaint;
-  java.util.List access$800(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  java.util.List mFaviconRects;
-  android.graphics.Paint mEmptyThumbnailPaint;
-  java.util.List access$1100(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  float access$500(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  java.util.List mFaviconBackgroundRects;
-  int mSize;
-  android.graphics.Paint access$700(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  org.chromium.chrome.browser.tabmodel.TabModelSelector access$100(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  org.chromium.chrome.browser.tabmodel.TabModelSelector mTabModelSelector;
-  android.graphics.Paint mThumbnailFramePaint;
-  org.chromium.chrome.browser.compositor.layouts.content.TabContentManager access$200(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  android.graphics.Paint access$400(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  java.util.List access$300(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  float mRadius;
-  float mFaviconCirclePadding;
-  android.graphics.Paint mFaviconBackgroundPaint;
-  android.graphics.Paint access$600(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-  org.chromium.chrome.browser.compositor.layouts.content.TabContentManager mTabContentManager;
-  int access$000(org.chromium.chrome.browser.tasks.tab_management.MultiThumbnailCardProvider);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridContainerViewBinder {
-  void bind(org.chromium.ui.modelutil.PropertyModel, org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView, org.chromium.ui.modelutil.PropertyKey);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridDialogCoordinator {
-  org.chromium.ui.modelutil.PropertyModel mToolbarPropertyModel;
-  android.content.Context mContext;
-  org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator mMediator;
-  void updateDialogContent(java.util.List);
-  org.chromium.chrome.browser.tasks.tab_management.TabGridSheetToolbarCoordinator mToolbarCoordinator;
-  org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator$ResetHandler getResetHandler();
-  org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator mTabListCoordinator;
-  void resetWithListOfTabs(java.util.List);
-  org.chromium.chrome.browser.tasks.tab_management.TabGridDialogParent mParentLayout;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator {
-  void setupToolbarClickHandlers();
-  org.chromium.chrome.browser.tabmodel.TabModelSelector mTabModelSelector;
-  void onReset(java.lang.Integer);
-  android.view.View$OnClickListener getCollapseButtonClickListener();
-  java.util.List getRelatedTabs(int);
-  void updateGridTabSwitcher();
-  org.chromium.ui.modelutil.PropertyModel mModel;
-  org.chromium.chrome.browser.tabmodel.TabModelObserver mTabModelObserver;
-  void lambda$getAddButtonClickListener$1(android.view.View);
-  void setupScrimViewObserver();
-  android.content.Context mContext;
-  void updateDialog();
-  org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator$ResetHandler mDialogResetHandler;
-  org.chromium.chrome.browser.tabmodel.TabCreatorManager mTabCreatorManager;
-  boolean $assertionsDisabled;
-  void access$100(org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator);
-  int access$400(org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator);
-  int access$402(org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator, int);
-  org.chromium.chrome.browser.tasks.tab_management.GridTabSwitcherMediator$ResetHandler mGridTabSwitcherResetHandler;
-  java.util.List access$300(org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator, int);
-  org.chromium.ui.modelutil.PropertyModel access$200(org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator);
-  void lambda$getCollapseButtonClickListener$0(android.view.View);
-  android.view.View$OnClickListener getAddButtonClickListener();
-  void access$000(org.chromium.chrome.browser.tasks.tab_management.TabGridDialogMediator);
-  int mCurrentTabId;
-  void destroy();
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridDialogParent {
-  void showDialog();
-  org.chromium.chrome.browser.widget.ScrimView$ScrimParams mScrimParams;
-  android.widget.PopupWindow mPopupWindow;
-  void setupDialogAnimation();
-  void destroy();
-  int mSideMargin;
-  void updateDialogWithOrientation(android.content.Context, int);
-  android.content.ComponentCallbacks mComponentCallbacks;
-  android.widget.LinearLayout mDialogContainerView;
-  void access$000(org.chromium.chrome.browser.tasks.tab_management.TabGridDialogParent, android.content.Context, int);
-  org.chromium.chrome.browser.widget.ScrimView mScrimView;
-  android.animation.Animator access$102(org.chromium.chrome.browser.tasks.tab_management.TabGridDialogParent, android.animation.Animator);
-  void hideDialog();
-  android.animation.ValueAnimator mDialogFadeOut;
-  android.view.ViewGroup mParent;
-  android.animation.Animator mCurrentAnimator;
-  int mTopMargin;
-  void setupDialogContent(android.content.Context);
-  void resetDialog(android.view.View, android.view.View);
-  android.widget.PopupWindow access$200(org.chromium.chrome.browser.tasks.tab_management.TabGridDialogParent);
-  android.animation.ValueAnimator mDialogFadeIn;
-  int mStatusBarHeight;
-  android.widget.FrameLayout$LayoutParams mContainerParams;
-  void setScrimViewObserver(org.chromium.chrome.browser.widget.ScrimView$ScrimObserver);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridSheetContent {
-  android.view.View mToolbarView;
-  void destroy();
-  org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView mRecyclerView;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridSheetCoordinator {
-  void updateBottomSheetContent(java.util.List);
-  org.chromium.chrome.browser.tasks.tab_management.TabGridSheetToolbarCoordinator mToolbarCoordinator;
-  org.chromium.ui.modelutil.PropertyModel mToolbarPropertyModel;
-  org.chromium.chrome.browser.tasks.tab_management.TabGridSheetContent mBottomSheetContent;
-  org.chromium.chrome.browser.tasks.tab_management.TabGridSheetMediator mMediator;
-  void destroy();
-  org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator mTabGridCoordinator;
-  void resetWithListOfTabs(java.util.List);
-  android.content.Context mContext;
-  void startObservingForCreationIPH();
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridSheetMediator {
-  android.view.View$OnClickListener getAddButtonClickListener();
-  org.chromium.chrome.browser.tabmodel.TabCreatorManager mTabCreatorManager;
-  void lambda$getAddButtonClickListener$3(android.view.View);
-  org.chromium.chrome.browser.tasks.tab_management.TabGridSheetMediator$ResetHandler mResetHandler;
-  org.chromium.chrome.browser.tabmodel.TabModelObserver mTabModelObserver;
-  void lambda$new$1(android.content.res.ColorStateList, boolean);
-  org.chromium.chrome.browser.ThemeColorProvider$ThemeColorObserver mThemeColorObserver;
-  void lambda$new$0(int, boolean);
-  void onReset(org.chromium.chrome.browser.tasks.tab_management.TabGridSheetContent);
-  void lambda$getCollapseButtonClickListener$2(android.view.View);
-  org.chromium.chrome.browser.widget.bottomsheet.BottomSheet$BottomSheetContent getCurrentSheetContent();
-  boolean $assertionsDisabled;
-  void setupToolbarClickHandlers();
-  android.content.Context mContext;
-  android.view.View$OnClickListener getCollapseButtonClickListener();
-  void destroy();
-  void showTabGridSheet(org.chromium.chrome.browser.tasks.tab_management.TabGridSheetContent);
-  void updateBottomSheet();
-  org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController mBottomSheetController;
-  org.chromium.chrome.browser.ThemeColorProvider mThemeColorProvider;
-  void access$000(org.chromium.chrome.browser.tasks.tab_management.TabGridSheetMediator);
-  org.chromium.ui.modelutil.PropertyModel mModel;
-  org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver mSheetObserver;
-  org.chromium.chrome.browser.ThemeColorProvider$TintObserver mTintObserver;
-  org.chromium.chrome.browser.tabmodel.TabModelSelector mTabModelSelector;
-  void hideTabGridSheet();
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties {
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey SCRIMVIEW_OBSERVER;
-  org.chromium.ui.modelutil.PropertyModel$WritableIntPropertyKey PRIMARY_COLOR;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey TINT;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey ADD_CLICK_LISTENER;
-  org.chromium.ui.modelutil.PropertyModel$WritableIntPropertyKey CONTENT_TOP_MARGIN;
-  org.chromium.ui.modelutil.PropertyModel$WritableBooleanPropertyKey IS_DIALOG_VISIBLE;
-  org.chromium.ui.modelutil.PropertyKey[] ALL_KEYS;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey COLLAPSE_CLICK_LISTENER;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey HEADER_TITLE;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridSheetToolbarCoordinator {
-  android.view.View getView();
-  org.chromium.chrome.browser.tasks.tab_management.TabGroupUiToolbarView mToolbarView;
-  org.chromium.ui.modelutil.PropertyModelChangeProcessor mModelChangeProcessor;
-  void destroy();
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridSheetViewBinder {
-  void bind(org.chromium.ui.modelutil.PropertyModel, org.chromium.chrome.browser.tasks.tab_management.TabGridSheetViewBinder$ViewHolder, org.chromium.ui.modelutil.PropertyKey);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridViewBinder {
-  void lambda$onBindViewHolder$3(org.chromium.chrome.browser.tasks.tab_management.TabListMediator$TabActionListener, org.chromium.chrome.browser.tasks.tab_management.TabGridViewHolder, android.view.View);
-  void lambda$onBindViewHolder$2(org.chromium.chrome.browser.tasks.tab_management.TabGridViewHolder, android.graphics.Bitmap);
-  void lambda$onBindViewHolder$0(org.chromium.ui.modelutil.PropertyModel, org.chromium.chrome.browser.tasks.tab_management.TabGridViewHolder, android.view.View);
-  void lambda$onBindViewHolder$1(org.chromium.ui.modelutil.PropertyModel, org.chromium.chrome.browser.tasks.tab_management.TabGridViewHolder, android.view.View);
-  void onBindViewHolder(org.chromium.chrome.browser.tasks.tab_management.TabGridViewHolder, org.chromium.ui.modelutil.PropertyModel);
-  void onBindViewHolder(org.chromium.chrome.browser.tasks.tab_management.TabGridViewHolder, org.chromium.ui.modelutil.PropertyModel, org.chromium.ui.modelutil.PropertyKey);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGridViewHolder {
-  android.widget.ImageView favicon;
-  int getTabId();
-  org.chromium.ui.widget.ButtonCompat createGroupButton;
-  android.widget.TextView title;
-  android.view.View backgroundView;
-  android.view.View itemView;
-  org.chromium.chrome.browser.tasks.tab_management.TabGridViewHolder create(android.view.ViewGroup, int);
-  void setTabId(int);
-  int mTabId;
-  java.lang.ref.WeakReference sCloseButtonBitmapWeakRef;
-  void resetThumbnail();
-  android.widget.ImageView thumbnail;
-  android.widget.ImageView closeButton;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGroupUiCoordinator {
-  org.chromium.ui.modelutil.PropertyModel mTabStripToolbarModel;
-  org.chromium.chrome.browser.ThemeColorProvider mThemeColorProvider;
-  android.content.Context mContext;
-  org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator mMediator;
-  org.chromium.chrome.browser.ChromeActivity mActivity;
-  org.chromium.chrome.browser.tasks.tab_management.TabGridSheetCoordinator mTabGridSheetCoordinator;
-  void recordSessionCount();
-  org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher mActivityLifecycleDispatcher;
-  org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator mTabStripCoordinator;
-  boolean $assertionsDisabled;
-  org.chromium.chrome.browser.tasks.tab_management.TabStripToolbarCoordinator mTabStripToolbarCoordinator;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator {
-  org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior mOverviewModeBehavior;
-  boolean mIsTabGroupUiVisible;
-  org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver mTabModelSelectorTabObserver;
-  org.chromium.chrome.browser.tabmodel.TabModelSelector access$400(org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator);
-  org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator$ResetHandler access$500(org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator);
-  java.util.List getRelatedTabsForId(int);
-  org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior$OverviewModeObserver mOverviewModeObserver;
-  org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver mTabModelSelectorObserver;
-  boolean access$100(org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator);
-  org.chromium.ui.modelutil.PropertyModel mToolbarPropertyModel;
-  org.chromium.chrome.browser.ThemeColorProvider$ThemeColorObserver mThemeColorObserver;
-  void lambda$setupToolbarClickHandlers$3(android.view.View);
-  org.chromium.chrome.browser.ThemeColorProvider mThemeColorProvider;
-  void lambda$setupToolbarClickHandlers$2(android.view.View);
-  void setupToolbarClickHandlers();
-  void lambda$new$1(android.content.res.ColorStateList, boolean);
-  void resetTabStripWithRelatedTabsForId(int);
-  org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator$BottomControlsVisibilityController mVisibilityController;
-  void destroy();
-  boolean $assertionsDisabled;
-  void lambda$new$0(int, boolean);
-  org.chromium.chrome.browser.tabmodel.TabModelObserver mTabModelObserver;
-  org.chromium.chrome.browser.ThemeColorProvider$TintObserver mTintObserver;
-  void access$300(org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator, int);
-  boolean mIsClosingAGroup;
-  org.chromium.chrome.browser.tabmodel.TabCreatorManager mTabCreatorManager;
-  org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator$ResetHandler mResetHandler;
-  org.chromium.chrome.browser.tabmodel.TabModelSelector mTabModelSelector;
-  boolean access$102(org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator, boolean);
-  java.util.List access$200(org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator, int);
-  boolean access$000(org.chromium.chrome.browser.tasks.tab_management.TabGroupUiMediator);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGroupUiToolbarView {
-  android.view.View mMainContent;
-  void setTint(android.content.res.ColorStateList);
-  android.view.ViewGroup mContainerView;
-  org.chromium.ui.widget.ChromeImageView mLeftButton;
-  void setMainContentVisibility(boolean);
-  void setTitle(java.lang.String);
-  org.chromium.ui.widget.ChromeImageView mRightButton;
-  android.view.View findViewById(int);
-  android.widget.TextView mTitleTextView;
-  void setLeftButtonOnClickListener(android.view.View$OnClickListener);
-  android.view.ViewGroup getViewContainer();
-  void setRightButtonOnClickListener(android.view.View$OnClickListener);
-  void setPrimaryColor(int);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabGroupUiToolbarViewBinder {
-  void bind(org.chromium.ui.modelutil.PropertyModel, org.chromium.chrome.browser.tasks.tab_management.TabGroupUiToolbarView, org.chromium.ui.modelutil.PropertyKey);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties {
-  org.chromium.ui.modelutil.PropertyModel$WritableIntPropertyKey TOP_PADDING;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey VISIBILITY_LISTENER;
-  org.chromium.ui.modelutil.PropertyModel$WritableIntPropertyKey INITIAL_SCROLL_INDEX;
-  org.chromium.ui.modelutil.PropertyModel$WritableBooleanPropertyKey ANIMATE_VISIBILITY_CHANGES;
-  org.chromium.ui.modelutil.PropertyKey[] ALL_KEYS;
-  org.chromium.ui.modelutil.PropertyModel$WritableIntPropertyKey BOTTOM_CONTROLS_HEIGHT;
-  org.chromium.ui.modelutil.PropertyModel$WritableBooleanPropertyKey IS_INCOGNITO;
-  org.chromium.ui.modelutil.PropertyModel$WritableBooleanPropertyKey IS_VISIBLE;
-  org.chromium.ui.modelutil.PropertyModel$WritableIntPropertyKey TOP_CONTROLS_HEIGHT;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator {
-  void updateThumbnailLocation();
-  org.chromium.chrome.browser.tabmodel.TabModelSelector mTabModelSelector;
-  android.graphics.Rect mThumbnailLocationOfCurrentTab;
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator mMediator;
-  org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView mRecyclerView;
-  int getResourceId();
-  android.graphics.Rect getThumbnailLocationOfCurrentTab();
-  int mMode;
-  void destroy();
-  org.chromium.ui.modelutil.SimpleRecyclerViewMcpBase mModelChangeProcessor;
-  org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView getContainerView();
-  void resetWithListOfTabs(java.util.List);
-  void prepareOverview();
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListFaviconProvider {
-  android.graphics.drawable.Drawable getDefaultFaviconDrawable();
-  android.graphics.drawable.Drawable getFaviconForUrlSync(java.lang.String, boolean, android.graphics.Bitmap);
-  android.graphics.drawable.Drawable sRoundedGlobeDrawable;
-  android.graphics.drawable.Drawable processBitmap(android.graphics.Bitmap);
-  int mFaviconSize;
-  void lambda$getFaviconForUrlAsync$0(org.chromium.base.Callback, android.graphics.Bitmap, java.lang.String);
-  android.graphics.drawable.Drawable sRoundedChromeDrawable;
-  org.chromium.chrome.browser.profiles.Profile mProfile;
-  void getFaviconForUrlAsync(java.lang.String, boolean, org.chromium.base.Callback);
-  org.chromium.chrome.browser.favicon.FaviconHelper mFaviconHelper;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListMediator {
-  void addTabInfoToModel(org.chromium.chrome.browser.tab.Tab, int, boolean);
-  boolean isValidMovePosition(int);
-  android.content.ComponentCallbacks mComponentCallbacks;
-  org.chromium.chrome.browser.tasks.tab_management.TabListFaviconProvider mTabListFaviconProvider;
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$GridCardOnClickListenerProvider mGridCardOnClickListenerProvider;
-  boolean mShownIPH;
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$TabActionListener access$1300(org.chromium.chrome.browser.tasks.tab_management.TabListMediator);
-  java.util.Map access$800();
-  org.chromium.chrome.browser.tabmodel.TabModelSelector access$100(org.chromium.chrome.browser.tasks.tab_management.TabListMediator);
-  boolean access$600(org.chromium.chrome.browser.tasks.tab_management.TabListMediator);
-  java.util.List access$1000(org.chromium.chrome.browser.tasks.tab_management.TabListMediator, int);
-  void access$900(org.chromium.chrome.browser.tasks.tab_management.TabListMediator, org.chromium.chrome.browser.tab.Tab, int, int);
-  void registerOrientationListener(android.support.v7.widget.GridLayoutManager);
-  java.lang.String mComponentName;
-  boolean mCloseAllRelatedTabs;
-  java.lang.String access$200(org.chromium.chrome.browser.tasks.tab_management.TabListMediator);
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$TitleProvider mTitleProvider;
-  android.support.v7.widget.helper.ItemTouchHelper$SimpleCallback getItemTouchHelperCallback(float);
-  void access$700(org.chromium.chrome.browser.tasks.tab_management.TabListMediator, org.chromium.chrome.browser.tab.Tab, boolean);
-  void onTabClosedFrom(int, java.lang.String);
-  boolean access$002(org.chromium.chrome.browser.tasks.tab_management.TabListMediator, boolean);
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$IphProvider mIphProvider;
-  java.util.Map sTabClosedFromMapTabClosedFromMap;
-  void onTabAdded(org.chromium.chrome.browser.tab.Tab, boolean);
-  org.chromium.chrome.browser.tab.TabObserver mTabObserver;
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$CreateGroupButtonProvider mCreateGroupButtonProvider;
-  java.util.List getRelatedTabsForId(int);
-  org.chromium.chrome.browser.tasks.tab_management.TabListFaviconProvider access$400(org.chromium.chrome.browser.tasks.tab_management.TabListMediator);
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$TabActionListener mTabSelectedListener;
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$TabActionListener mTabClosedListener;
-  void resetWithListOfTabs(java.util.List);
-  org.chromium.chrome.browser.tabmodel.TabModelSelector mTabModelSelector;
-  boolean access$000(org.chromium.chrome.browser.tasks.tab_management.TabListMediator);
-  void lambda$addTabInfoToModel$0(org.chromium.chrome.browser.tab.Tab, android.graphics.drawable.Drawable);
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$ThumbnailProvider mThumbnailProvider;
-  void onGroupClosedFrom(int);
-  org.chromium.chrome.browser.tasks.tab_management.TabListModel mModel;
-  org.chromium.chrome.browser.tabmodel.TabModelObserver mTabModelObserver;
-  void onTabMoved(org.chromium.chrome.browser.tab.Tab, int, int);
-  void access$1200(org.chromium.chrome.browser.tasks.tab_management.TabListMediator, int, java.lang.String);
-  org.chromium.chrome.browser.tasks.tab_management.TabListModel access$300(org.chromium.chrome.browser.tasks.tab_management.TabListMediator);
-  org.chromium.chrome.browser.tasks.tab_management.TabListMediator$TitleProvider access$500(org.chromium.chrome.browser.tasks.tab_management.TabListMediator);
-  void access$1100(org.chromium.chrome.browser.tasks.tab_management.TabListMediator, int);
-  void destroy();
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListModel {
-  void add(int, org.chromium.ui.modelutil.PropertyObservable);
-  int size();
-  void add(org.chromium.ui.modelutil.PropertyObservable);
-  java.lang.Object get(int);
-  org.chromium.ui.modelutil.PropertyObservable removeAt(int);
-  void set(java.util.Collection);
-  int indexFromId(int);
-  void move(int, int);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView {
-  int getId();
-  long access$200(org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView);
-  android.graphics.Rect getRectOfCurrentThumbnail(int);
-  void setHasFixedSize(boolean);
-  android.animation.ValueAnimator mFadeInAnimator;
-  int getPaddingLeft();
-  int getPaddingBottom();
-  void endAllAnimations();
-  long mOriginalAddDuration;
-  int getResourceId();
-  org.chromium.ui.resources.dynamics.ViewResourceAdapter access$300(org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView);
-  org.chromium.ui.resources.dynamics.ViewResourceAdapter mDynamicView;
-  int computeVerticalScrollOffset();
-  org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView$VisibilityListener mListener;
-  void startShowing(boolean);
-  android.animation.ValueAnimator access$002(org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView, android.animation.ValueAnimator);
-  void setBackgroundColor(int);
-  void setAlpha(float);
-  void setVisibilityListener(org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView$VisibilityListener);
-  android.animation.ValueAnimator mFadeOutAnimator;
-  void setVisibility(int);
-  android.view.ViewTreeObserver getViewTreeObserver();
-  void setPadding(int, int, int, int);
-  android.support.v7.widget.RecyclerView$LayoutManager getLayoutManager();
-  boolean $assertionsDisabled;
-  void createDynamicView(org.chromium.ui.resources.dynamics.DynamicResourceLoader);
-  android.content.res.Resources getResources();
-  android.animation.ValueAnimator access$402(org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView, android.animation.ValueAnimator);
-  void prepareOverview();
-  void setAdapter(android.support.v7.widget.RecyclerView$Adapter);
-  android.support.v7.widget.RecyclerView$ItemAnimator getItemAnimator();
-  void requestLayout();
-  android.view.ViewGroup$LayoutParams getLayoutParams();
-  android.support.v7.widget.RecyclerView$ViewHolder findViewHolderForAdapterPosition(int);
-  void setLayoutManager(android.support.v7.widget.RecyclerView$LayoutManager);
-  void getLocationInWindow(int[]);
-  void startHiding(boolean);
-  int getPaddingRight();
-  org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView$VisibilityListener access$100(org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabProperties {
-  org.chromium.ui.modelutil.PropertyModel$ReadableIntPropertyKey TAB_ID;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey IPH_PROVIDER;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey CREATE_GROUP_LISTENER;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey TAB_SELECTED_LISTENER;
-  org.chromium.ui.modelutil.PropertyKey[] ALL_KEYS_TAB_GRID;
-  org.chromium.ui.modelutil.PropertyKey[] ALL_KEYS_TAB_STRIP;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey FAVICON;
-  org.chromium.ui.modelutil.PropertyModel$WritableBooleanPropertyKey IS_SELECTED;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey TITLE;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey TAB_CLOSED_LISTENER;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey THUMBNAIL_FETCHER;
-  org.chromium.ui.modelutil.PropertyModel$WritableFloatPropertyKey ALPHA;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabStripToolbarCoordinator {
-  android.view.ViewGroup getTabListContainerView();
-  org.chromium.ui.modelutil.PropertyModel mModel;
-  org.chromium.ui.modelutil.PropertyModelChangeProcessor mModelChangeProcessor;
-  org.chromium.chrome.browser.tasks.tab_management.TabGroupUiToolbarView mToolbarView;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabStripToolbarViewProperties {
-  org.chromium.ui.modelutil.PropertyModel$WritableIntPropertyKey PRIMARY_COLOR;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey ADD_CLICK_LISTENER;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey TINT;
-  org.chromium.ui.modelutil.PropertyKey[] ALL_KEYS;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey EXPAND_CLICK_LISTENER;
-  org.chromium.ui.modelutil.PropertyModel$WritableBooleanPropertyKey IS_MAIN_CONTENT_VISIBLE;
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabStripViewBinder {
-  void lambda$onBindViewHolder$1(org.chromium.ui.modelutil.PropertyModel, org.chromium.chrome.browser.tasks.tab_management.TabStripViewHolder, android.view.View);
-  void lambda$onBindViewHolder$0(org.chromium.ui.modelutil.PropertyModel, org.chromium.chrome.browser.tasks.tab_management.TabStripViewHolder, android.view.View);
-  void onBindViewHolder(org.chromium.chrome.browser.tasks.tab_management.TabStripViewHolder, org.chromium.ui.modelutil.PropertyModel, org.chromium.ui.modelutil.PropertyKey);
-  void onBindViewHolder(org.chromium.chrome.browser.tasks.tab_management.TabStripViewHolder, org.chromium.ui.modelutil.PropertyModel);
-}
-
--keep class org.chromium.chrome.browser.tasks.tab_management.TabStripViewHolder {
-  android.widget.ImageButton button;
-  int mTabId;
-  android.view.View itemView;
-  org.chromium.chrome.browser.tasks.tab_management.TabStripViewHolder create(android.view.ViewGroup, int);
-  void setTabId(int);
-  int getTabId();
-}
-
--keep class org.chromium.chrome.browser.tasks.tabgroup.TabGroupModelFilter {
-  int indexOf(org.chromium.chrome.browser.tab.Tab);
-  int getTabGroupCount();
-  void recordSessionsCount(org.chromium.chrome.browser.tab.Tab);
-  void moveRelatedTabs(int, int);
-  org.chromium.chrome.browser.tab.Tab getTabAt(int);
-}
-
--keep class org.chromium.chrome.browser.util.ColorUtils {
-  int getPrimaryBackgroundColor(android.content.res.Resources, boolean);
-}
-
--keep class org.chromium.chrome.browser.util.FeatureUtilities {
-  boolean isTabGroupsAndroidEnabled();
-  boolean isTabGroupsAndroidUiImprovementsEnabled();
-}
-
--keep class org.chromium.chrome.browser.util.ViewUtils {
-  android.support.v4.graphics.drawable.RoundedBitmapDrawable createRoundedBitmapDrawable(android.graphics.Bitmap, int);
-  int DEFAULT_FAVICON_CORNER_RADIUS;
-}
-
--keep class org.chromium.chrome.browser.widget.bottomsheet.BottomSheet {
-  void addObserver(org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver);
-  void removeObserver(org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver);
-  org.chromium.chrome.browser.widget.bottomsheet.BottomSheet$BottomSheetContent getCurrentSheetContent();
-}
-
--keep class org.chromium.content_public.browser.NavigationHandle {
-  boolean isSameDocument();
-  boolean isValidSearchFormUrl();
-  boolean isInMainFrame();
-  java.lang.Integer pageTransition();
-}
-
--keep class org.chromium.content_public.browser.UiThreadTaskTraits {
-  org.chromium.base.task.TaskTraits USER_VISIBLE;
-}
-
--keep class org.chromium.ui.interpolators.BakedBezierInterpolator {
-  org.chromium.ui.interpolators.BakedBezierInterpolator FADE_IN_CURVE;
-  org.chromium.ui.interpolators.BakedBezierInterpolator FADE_OUT_CURVE;
-}
-
--keep class org.chromium.ui.modelutil.PropertyModelChangeProcessor {
-  void destroy();
-  org.chromium.ui.modelutil.PropertyModelChangeProcessor create(org.chromium.ui.modelutil.PropertyObservable, java.lang.Object, org.chromium.ui.modelutil.PropertyModelChangeProcessor$ViewBinder);
-}
-
--keep class org.chromium.ui.widget.ButtonCompat {
-  void setVisibility(int);
-  void setOnClickListener(android.view.View$OnClickListener);
-}
-
--keep class org.chromium.ui.widget.ChromeImageView {
-  void setOnClickListener(android.view.View$OnClickListener);
-}
-
--keep class org.json.JSONObject {
-  java.lang.Object NULL;
-}
-
diff --git a/chrome/android/features/tab_ui/proguard_async_manual.flags b/chrome/android/features/tab_ui/proguard_async_manual.flags
deleted file mode 100644
index 654ee65..0000000
--- a/chrome/android/features/tab_ui/proguard_async_manual.flags
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Rules added manually due to types
-#   1) used and included in XML files (ie. layout),
-#   2) dynamically generated by the compiler (ie. lambda), and
-#   3) types not currently being included in our constant pool deps.
-
--keep class android.support.v4.graphics.drawable.RoundedBitmapDrawable { *; }
--keep class org.chromium.ui.widget.RoundedCornerImageView { *; }
--keep class org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager$FullscreenListener$$CC { *; }
--keep class org.chromium.chrome.browser.widget.bottomsheet.BottomSheet$BottomSheetContent$$CC { *; }
--keep class org.chromium.chrome.browser.compositor.layouts.OverviewModeController { *; }
\ No newline at end of file
diff --git a/chrome/android/features/tab_ui/tab_ui_module.gni b/chrome/android/features/tab_ui/tab_ui_module.gni
index c3b61ed..e153234 100644
--- a/chrome/android/features/tab_ui/tab_ui_module.gni
+++ b/chrome/android/features/tab_ui/tab_ui_module.gni
@@ -8,5 +8,4 @@
   name = "tab_ui"
   java_deps = [ "//chrome/android/features/tab_ui:java" ]
   android_manifest = "//chrome/android/features/tab_ui/AndroidManifest.xml"
-  proguard_async = async_tab_ui
 }
diff --git a/chrome/android/features/vr/BUILD.gn b/chrome/android/features/vr/BUILD.gn
index c38cbc2..feabb434 100644
--- a/chrome/android/features/vr/BUILD.gn
+++ b/chrome/android/features/vr/BUILD.gn
@@ -134,9 +134,6 @@
     "//ui/android:ui_utils_java",
   ]
 
-  if (async_vr) {
-    proguard_configs = [ "//base/android/proguard/chromium_code.flags" ]
-  }
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
 }
 
diff --git a/chrome/android/features/vr/proguard_async.flags b/chrome/android/features/vr/proguard_async.flags
deleted file mode 100644
index 59b5fa1..0000000
--- a/chrome/android/features/vr/proguard_async.flags
+++ /dev/null
@@ -1,6813 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Contains flags necessary to keep the VR module compatible with base when VR
-# is specified as an async DFM (when the VR module is proguarded separately).
-# This flags file was generated from the dependencies of Java classes in
-# the VR module, produced by reading from their constant pools. It
-# intentionally keeps all members from these dependencies to ensure
-# compatibility between the async VR module and base.
-
--keep,allowobfuscation class com.google.devtools.build.android.desugar.runtime.ThrowableExtension$AbstractDesugaringStrategy { *; }
-
--keep,allowobfuscation class com.google.protobuf.nano.ExtendableMessageNano { *; }
-
--keep,allowobfuscation class com.google.protobuf.nano.Extension { *; }
-
--keep,allowobfuscation class com.google.protobuf.nano.MessageNano { *; }
-
--keep,allowobfuscation class com.google.vr.cardboard.DisplaySynchronizer { *; }
-
--keep,allowobfuscation class com.google.vr.cardboard.EglReadyListener$EventListener { *; }
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurfaceCallback { *; }
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$UpdateSurfaceCallback { *; }
-
--keep,allowobfuscation class com.google.vr.cardboard.VrParamsProvider { *; }
-
--keep,allowobfuscation class com.google.vr.internal.controller.ControllerServiceBridge$Callbacks { *; }
-
--keep,allowobfuscation class com.google.vr.keyboard.IGvrKeyboardLoader { *; }
-
--keep,allowobfuscation class com.google.vr.ndk.base.AbstractDaydreamTouchListener { *; }
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrApi$IdleListener { *; }
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayout { *; }
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView { *; }
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$BaseConfigChooser { *; }
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$ComponentSizeChooser { *; }
-
--keep,allowobfuscation class com.google.vr.sdk.common.deps.a { *; }
-
--keep,allowobfuscation class com.google.vr.sdk.common.deps.b { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.base.api.ParcelableProto { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IDaydreamListener { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IDaydreamListener$Stub { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IDaydreamManager { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.ITransitionCallbacks { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.ITransitionCallbacks$Stub { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IVrCoreSdkService { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerEvent { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerEventPacket { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerListener { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerListener$Stub { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerService { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerServiceListener { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerServiceListener$Stub { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IGvrLayout { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IGvrLayout$Stub { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IGvrUiLayout { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IGvrUiLayout$Stub { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IObjectWrapper { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IObjectWrapper$Stub { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IVrCreator { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IVrNativeLibraryLoader { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.logging.api.IVrCoreLoggingService { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.performance.api.IPerformanceService { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.performance.api.IThrottlingTriggerCallback { *; }
-
--keep,allowobfuscation class com.google.vr.vrcore.performance.api.IThrottlingTriggerCallback$Stub { *; }
-
--keep,allowobfuscation class org.apache.http.conn.scheme.LayeredSocketFactory { *; }
-
--keep,allowobfuscation class org.apache.http.conn.scheme.SocketFactory { *; }
-
--keep,allowobfuscation class org.apache.http.conn.ssl.AbstractVerifier { *; }
-
--keep,allowobfuscation class org.apache.http.conn.ssl.X509HostnameVerifier { *; }
-
--keep,allowobfuscation class org.apache.http.params.CoreConnectionPNames { *; }
-
--keep,allowobfuscation class org.chromium.base.ApplicationStatus$ActivityStateListener { *; }
-
--keep,allowobfuscation class org.chromium.base.task.AsyncTask { *; }
-
--keep,allowobfuscation class org.chromium.build.BuildHooksAndroid { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.compositor.CompositorSurfaceManager { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder$Listener { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.tab.EmptyTabObserver { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.tab.TabRedirectHandler { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.EmptySniffingVrViewContainer$EmptyListener { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.NoopCanvas$NoopException { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.OnExitVrRequestListener { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrDelegate { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrDelegateProvider { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrDialogManager { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrIntentDelegate { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrToastManager { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrViewContainer { *; }
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.keyboard.VrInputMethodManagerWrapper$BrowserKeyboardInterface { *; }
-
--keep,allowobfuscation class org.chromium.content_public.browser.InputMethodManagerWrapper { *; }
-
--keep,allowobfuscation class org.chromium.content_public.browser.ScreenOrientationDelegate { *; }
-
--keep,allowobfuscation class org.chromium.ui.base.AndroidPermissionDelegate { *; }
-
--keep,allowobfuscation class org.chromium.ui.base.PermissionCallback { *; }
-
--keep,allowobfuscation class org.chromium.ui.base.WindowAndroid { *; }
-
--keep,allowobfuscation class org.chromium.ui.modaldialog.ModalDialogManager$Presenter { *; }
-
--keep,allowobfuscation class org.chromium.ui.modaldialog.ModalDialogProperties$Controller { *; }
-
--keep,allowobfuscation class org.chromium.ui.widget.UiWidgetFactory { *; }
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent {
-  com.google.common.logging.nano.Vr$VREvent$Eva eva;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr earthVr;
-  com.google.common.logging.nano.Vr$VREvent$Expeditions expeditions;
-  java.lang.Long durationMs;
-  int checkEventSourceOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$VrCore vrCore;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$VrHome vrHome;
-  com.google.common.logging.nano.Vr$VREvent$Launcher launcher;
-  com.google.common.logging.nano.Vr$VREvent$Renderer renderer;
-  com.google.common.logging.nano.Vr$VREvent$Cyclops cyclops;
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset standaloneHeadset;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector jumpInspector;
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate gConfigUpdate;
-  com.google.common.logging.nano.Vr$VREvent$Photos photos;
-  com.google.common.logging.nano.VrBaseOuterClass$VrBase$HeadMount headMount;
-  int checkBucketOrThrow(int);
-  byte[] toByteArray(com.google.protobuf.nano.MessageNano);
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking headTracking;
-  com.google.common.logging.nano.Vr$VREvent$PhoneAlignment phoneAlignment;
-  com.google.common.logging.nano.Vr$VREvent$Application application;
-  com.google.common.logging.nano.Vr$VREvent$QrCodeScan qrCodeScan;
-  com.google.common.logging.nano.Vr$VREvent$StreetView streetView;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams sdkConfiguration;
-  com.google.common.logging.nano.Vr$VREvent$Lullaby lullaby;
-  com.google.common.logging.nano.Vr$VREvent clear();
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming vrStreaming;
-  java.lang.Integer eventSource;
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget embedVrWidget;
-  com.google.common.logging.nano.Vr$VREvent$AudioStats audioStats;
-  com.google.common.logging.nano.Vr$VREvent clone();
-  java.lang.String cohort;
-  com.google.common.logging.nano.Vr$VREvent$SensorStats sensorStats;
-  com.google.common.logging.nano.Vr$VREvent parseFrom(byte[]);
-  com.google.common.logging.nano.Vr$VREvent$Application[] installedVrApplications;
-  com.google.common.logging.nano.Vr$VREvent$Keyboard keyboard;
-  java.lang.Integer lifetimeCountBucket;
-  com.google.common.logging.nano.Vr$VREvent$PerformanceStats performanceStats;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Application {
-  com.google.common.logging.nano.Vr$VREvent$Application[] emptyArray();
-  com.google.common.logging.nano.Vr$VREvent$Application clear();
-  com.google.common.logging.nano.Vr$VREvent$Application clone();
-  java.lang.String packageName;
-  java.lang.String version;
-  com.google.common.logging.nano.Vr$VREvent$Application[] _emptyArray;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Application mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  java.lang.String name;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$AudioStats {
-  com.google.common.logging.nano.Vr$VREvent$AudioStats clone();
-  com.google.common.logging.nano.Vr$VREvent$AudioStats clear();
-  java.lang.Integer framesPerBuffer;
-  int checkRenderingModeOrThrow(int);
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$AudioStats mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer renderingMode;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] numberOfSimultaneousSoundFields;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] cpuMeasurementsPercent;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] numberOfSimultaneousSoundObjects;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] renderingTimePerBufferMilliseconds;
-  java.lang.Integer sampleRate;
-  int cachedSize;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Cyclops {
-  com.google.common.logging.nano.Vr$VREvent$Cyclops mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$Share share;
-  com.google.common.logging.nano.Vr$VREvent$Cyclops clear();
-  com.google.common.logging.nano.Vr$VREvent$Cyclops clone();
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$View view;
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$Capture capture;
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$ShareStart shareStart;
-  int cachedSize;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Cyclops$Capture {
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$Capture clear();
-  java.lang.Integer outcome;
-  java.lang.Long compositionTimeMs;
-  java.lang.Boolean captureWarnings;
-  int cachedSize;
-   <init>();
-  int checkOutcomeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$Capture clone();
-  java.lang.Long captureTimeMs;
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$Capture mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Boolean withSound;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Float angleDegrees;
-  java.lang.Long processingTimeMs;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Cyclops$Share {
-  int checkTypeOrThrow(int);
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$Share clone();
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$Share clear();
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Integer numPhotos;
-  java.lang.Boolean withSound;
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$Share mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  java.lang.Integer type;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Cyclops$ShareStart {
-  java.lang.Integer originScreen;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$ShareStart mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$ShareStart clone();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$ShareStart clear();
-  int checkOriginScreenOrThrow(int);
-  java.lang.Integer numPhotos;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Cyclops$View {
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$View clear();
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$View clone();
-  java.lang.Boolean interaction;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer orientation;
-   <init>();
-  int checkOrientationOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$Cyclops$View mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Boolean withSound;
-  java.lang.Integer numPanos;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$DoublePrecisionTransform {
-  java.lang.Double translationY;
-  java.lang.Double rotationQz;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$DoublePrecisionTransform clone();
-  com.google.common.logging.nano.Vr$VREvent$DoublePrecisionTransform clear();
-  java.lang.Double rotationQx;
-  com.google.common.logging.nano.Vr$VREvent$DoublePrecisionTransform mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  java.lang.Double rotationQy;
-  java.lang.Double translationX;
-  java.lang.Double translationZ;
-  java.lang.Double scale;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr {
-  com.google.common.logging.nano.Vr$VREvent$DoublePrecisionTransform startFromKeyholeTransform;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$StreetView streetView;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Search search;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Environment environment;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr clone();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$VrSdkError[] errors;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr clear();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Tour tour;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Preferences preferences;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Preferences preferencesDelta;
-  com.google.common.logging.nano.Vr$VREvent$Transform startFromHeadTransform;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Tutorial tutorial;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor[] actors;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$ControllerState[] controllerStates;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$SplashScreen splashScreen;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$ActionOrb actionOrb;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$View view;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$AppState appState;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Menu menu;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$ActionOrb {
-  java.lang.Integer displayMode;
-   <init>();
-  int checkExpansionStateOrThrow(int);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Integer previousDisplayMode;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$ActionOrb clone();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$ActionOrb clear();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$ActionOrb mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer previousExpansionState;
-  int cachedSize;
-  int checkDisplayModeOrThrow(int);
-  java.lang.Integer expansionState;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor {
-  java.lang.Integer vrSdk;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor[] emptyArray();
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor clear();
-  com.google.common.logging.nano.Vr$VREvent$Transform startFromHeadTransform;
-  int checkVrSystemTypeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int checkVrSdkOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor clone();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor$ControllerState[] controllerStates;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer vrSystemType;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor[] _emptyArray;
-  int cachedSize;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor$ControllerState {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor$ControllerState clear();
-  int cachedSize;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$Transform startFromControllerTransform;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor$ControllerState clone();
-  java.lang.Integer type;
-  int checkRoleOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor$ControllerState[] emptyArray();
-   <init>();
-  java.lang.Integer role;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor$ControllerState[] _emptyArray;
-  int checkTypeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Actor$ControllerState mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$AppState {
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$AppState clear();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$AppState clone();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$AppState mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Long appModeId;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$ControllerState {
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Transform startFromControllerTransform;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$ControllerState mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$ControllerState clone();
-  java.lang.Integer role;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$ControllerState clear();
-  int checkRoleOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$ControllerState[] emptyArray();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$ControllerState[] _emptyArray;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$Environment {
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Environment mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Environment clear();
-  com.google.common.logging.nano.Vr$VREvent$Transform startFromEnvironmentTransform;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Environment clone();
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$GeoLocation {
-  java.lang.Double altitudeMeters;
-   <init>();
-  java.lang.Double latitudeDegrees;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$GeoLocation mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-  java.lang.Double longitudeDegrees;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$GeoLocation clone();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$GeoLocation clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$Menu {
-   <init>();
-  java.lang.String contentKey;
-  java.lang.Integer pageIndex;
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Menu clone();
-  java.lang.String contentName;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Menu clear();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Menu mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.String categoryName;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$Preferences {
-  java.lang.Integer humanScaleMode;
-  java.lang.Integer comfortModeState;
-  int checkStartConfigurationOrThrow(int);
-  java.lang.Integer startConfiguration;
-   <init>();
-  int cachedSize;
-  int checkComfortModeStateOrThrow(int);
-  int checkLabelsStateOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Preferences clear();
-  java.lang.Integer labelsState;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Preferences clone();
-  int checkGuestModeOrThrow(int);
-  int checkHumanScaleModeOrThrow(int);
-  java.lang.Integer guestMode;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Preferences mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$Search {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.String typedQuery;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Search clone();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Search clear();
-  java.lang.Integer selectedEntityIndex;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Search mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$View selectedEntityView;
-   <init>();
-  java.lang.String searchQuery;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$SplashScreen {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Long numberOfViewPreloadsSucceeded;
-  int cachedSize;
-  java.lang.Long viewPreloadDurationMs;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$SplashScreen clear();
-  java.lang.Long numberOfViewPreloadsAttempted;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$SplashScreen clone();
-  int checkExitTypeOrThrow(int);
-  java.lang.Integer exitType;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$SplashScreen mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$StreetView {
-   <init>();
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  int checkStateOrThrow(int);
-  int checkPanoTypeOrThrow(int);
-  int cachedSize;
-  java.lang.String panoId;
-  java.lang.Integer panoType;
-  java.lang.Integer panoFrontend;
-  java.lang.Integer panoNeighborCount;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$StreetView mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Boolean hasUserDiscoveredNeighbor;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$StreetView clone();
-  int checkPanoFrontendOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$StreetView clear();
-  java.lang.Integer previousState;
-  java.lang.Integer state;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$GeoLocation panoLocation;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$Tour {
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Tour clone();
-  java.lang.Long playbackMs;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Tour clear();
-  java.lang.String name;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Tour mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$Tutorial {
-   <init>();
-  java.lang.String stageName;
-  java.lang.Integer stage;
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Tutorial clone();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Tutorial clear();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$Tutorial mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$View {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Long simulationSecondsSinceEpoch;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$View mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer mode;
-  int cachedSize;
-  java.lang.Integer forceHumanScale;
-  java.lang.Double logicalViewerScale;
-  int checkModeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$DoublePrecisionTransform startFromKeyholeTransform;
-   <init>();
-  int checkForceHumanScaleOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$View clear();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$View clone();
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EarthVr$VrSdkError {
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$VrSdkError[] _emptyArray;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$VrSdkError mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer sdkErrorCode;
-  java.lang.Integer shutdownReason;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$VrSdkError clear();
-  int checkShutdownReasonOrThrow(int);
-  java.lang.String sdkFunction;
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$VrSdkError[] emptyArray();
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$EarthVr$VrSdkError clone();
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget {
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget$Video video;
-  int checkStereoFormatOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget$Pano pano;
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer viewMode;
-  int cachedSize;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  int checkViewModeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget clone();
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget clear();
-  java.lang.String errorMsg;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget$Pano {
-  java.lang.Integer widthPixels;
-  java.lang.Integer stereoFormat;
-  int cachedSize;
-  java.lang.Integer heightPixels;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget$Pano clone();
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget$Pano mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget$Pano clear();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget$Video {
-  java.lang.Integer heightPixels;
-  java.lang.Integer stereoFormat;
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget$Video mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget$Video clear();
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  int cachedSize;
-   <init>();
-  java.lang.Integer widthPixels;
-  com.google.common.logging.nano.Vr$VREvent$EmbedVrWidget$Video clone();
-  java.lang.Integer videoDurationMs;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Eva {
-  com.google.common.logging.nano.Vr$VREvent$Eva$CameraStatus cameraStatus;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Eva$View view;
-  com.google.common.logging.nano.Vr$VREvent$Eva$BluetoothSession bluetoothSession;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Eva$FileTransfer fileTransfer;
-  com.google.common.logging.nano.Vr$VREvent$Eva clone();
-  com.google.common.logging.nano.Vr$VREvent$Eva$Capture capture;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Eva mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Eva$CameraInfo cameraType;
-  com.google.common.logging.nano.Vr$VREvent$Eva$Pairing pairing;
-  com.google.common.logging.nano.Vr$VREvent$Eva clear();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Eva$BluetoothSession {
-  java.lang.Integer failedRequestCount;
-  com.google.common.logging.nano.Vr$VREvent$Eva$BluetoothSession clear();
-  java.lang.Integer requestCount;
-  java.lang.Long receivedBytes;
-  com.google.common.logging.nano.Vr$VREvent$Eva$BluetoothSession clone();
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer statusUpdateNotificationCount;
-  int cachedSize;
-  java.lang.Long sentBytes;
-  com.google.common.logging.nano.Vr$VREvent$Eva$BluetoothSession mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Long totalLatencyMs;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Eva$CameraInfo {
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer cameraType;
-  java.lang.String firmwareVersion;
-  com.google.common.logging.nano.Vr$VREvent$Eva$CameraInfo mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int checkCameraTypeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$Eva$CameraInfo clear();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Eva$CameraInfo clone();
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Eva$CameraStatus {
-  java.lang.Boolean batteryCharging;
-  java.lang.Integer deviceTemperature;
-  java.lang.Long freeStorage;
-  java.lang.Boolean phoneToCameraWifi;
-  int cachedSize;
-  java.lang.Boolean recording;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Eva$CameraStatus clear();
-  com.google.common.logging.nano.Vr$VREvent$Eva$CameraStatus mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Eva$CameraStatus clone();
-  java.lang.Long totalStorage;
-  java.lang.Boolean connectedToWifi;
-  java.lang.Integer batteryPercentage;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Eva$Capture {
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  int checkCaptureTypeOrThrow(int);
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Eva$Capture clone();
-  java.lang.Integer captureType;
-  com.google.common.logging.nano.Vr$VREvent$Eva$Resolution resolution;
-  com.google.common.logging.nano.Vr$VREvent$Eva$Capture mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Eva$VideoInfo videoInfo;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Eva$Capture clear();
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Eva$FileTransfer {
-  java.lang.Integer outcome;
-  com.google.common.logging.nano.Vr$VREvent$Eva$Resolution resolution;
-  java.lang.Integer fileType;
-  int cachedSize;
-   <init>();
-  int checkFileTypeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$Eva$FileTransfer clear();
-  java.lang.Integer transferInterface;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Eva$VideoInfo videoInfo;
-  java.lang.Long transferTimeMs;
-  com.google.common.logging.nano.Vr$VREvent$Eva$FileTransfer clone();
-  int checkOutcomeOrThrow(int);
-  int checkTransferInterfaceOrThrow(int);
-  java.lang.Long fileSize;
-  com.google.common.logging.nano.Vr$VREvent$Eva$FileTransfer mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Eva$Pairing {
-  java.lang.Long bluetoothPairingTimeMs;
-  java.lang.Long pairingFlowTimeMs;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  java.lang.Integer outcome;
-  com.google.common.logging.nano.Vr$VREvent$Eva$Pairing clone();
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Eva$Pairing mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Eva$Pairing clear();
-  int checkOutcomeOrThrow(int);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Eva$Resolution {
-   <init>();
-  int cachedSize;
-  java.lang.Integer height;
-  com.google.common.logging.nano.Vr$VREvent$Eva$Resolution mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Eva$Resolution clone();
-  java.lang.Integer width;
-  com.google.common.logging.nano.Vr$VREvent$Eva$Resolution clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Eva$VideoInfo {
-   <init>();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Eva$VideoInfo clone();
-  com.google.common.logging.nano.Vr$VREvent$Eva$VideoInfo mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Long durationMs;
-  java.lang.Integer codec;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Eva$VideoInfo clear();
-  int checkCodecOrThrow(int);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Eva$View {
-  com.google.common.logging.nano.Vr$VREvent$Eva$View clone();
-  int cachedSize;
-  java.lang.Integer viewType;
-  java.lang.Integer mediaType;
-  java.lang.Integer viewSource;
-  int checkViewSourceOrThrow(int);
-  int checkMediaTypeOrThrow(int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Eva$View clear();
-  java.lang.Long loadingTimeMs;
-  int checkViewTypeOrThrow(int);
-  java.lang.Long viewingDurationMs;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Eva$View mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Expeditions {
-  com.google.common.logging.nano.Vr$VREvent$Expeditions clear();
-  com.google.common.logging.nano.Vr$VREvent$Expeditions mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  int cachedSize;
-  java.lang.String contentId;
-  com.google.common.logging.nano.Vr$VREvent$Expeditions clone();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$GConfigUpdate {
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate clone();
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate clear();
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate$GConfigValue[] gConfigValue;
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$GConfigUpdate$GConfigValue {
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate$GConfigValue[] _emptyArray;
-  java.lang.String gConfigKey;
-  java.lang.String stringValue;
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate$GConfigValue mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate$GConfigValue clear();
-  int cachedSize;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate$GConfigValue[] emptyArray();
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate$GConfigValue clone();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$HeadTracking {
-  java.lang.Long sixDofFallbackTimestamp;
-  int oneof_safety_config_;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking clear();
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$SafetyCylinderConfig safetyCylinderConfig;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport periodicReport;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer sixDofFallbackReason;
-  int checkFallBackReasonOrThrow(int);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Float floorHeight;
-  java.lang.Long headTrackingTimestamp;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking clone();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport {
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport clear();
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$SafeRegionEvent[] safeRegionEvent;
-  int cachedSize;
-  java.lang.Long endTimestampMs;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$RecenterEvent[] recenterEvent;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Long startTimestampMs;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport clone();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$RecenterEvent {
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$RecenterEvent[] _emptyArray;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$RecenterEvent[] emptyArray();
-   <init>();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$RecenterEvent clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer type;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$RecenterEvent clone();
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$RecenterEvent mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Long timestampMs;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$SafeRegionEvent {
-   <init>();
-  float[] hrsQuat;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  java.lang.Long timestampMs;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$SafeRegionEvent[] emptyArray();
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$SafeRegionEvent clear();
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$SafeRegionEvent clone();
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$SafeRegionEvent[] _emptyArray;
-  float[] hrsPosition;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$PeriodicReport$SafeRegionEvent mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Boolean entered;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$HeadTracking$SafetyCylinderConfig {
-  java.lang.Float exitEventRadius;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$SafetyCylinderConfig clear();
-  java.lang.Float outerRadius;
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  float[] innerFogColor;
-  java.lang.Float collisionSphereRadius;
-  float[] outerFogColor;
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$SafetyCylinderConfig clone();
-  com.google.common.logging.nano.Vr$VREvent$HeadTracking$SafetyCylinderConfig mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Float anchorWarningDistance;
-  java.lang.Float enterEventRadius;
-  java.lang.Float innerRadius;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$HistogramBucket {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] _emptyArray;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-  int cachedSize;
-  java.lang.Integer count;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] emptyArray();
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket clear();
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket clone();
-  java.lang.Integer minimumValue;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector {
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$PlaybackDetails playbackDetails;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$PickerDetails pickerEvent;
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$MediaDetails mediaDetails;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector clone();
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector clear();
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector$AudioDetails {
-  java.lang.Long mediaLengthSeconds;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$AudioDetails clear();
-  java.lang.Integer audioBitRate;
-  java.lang.Integer audioCodec;
-  java.lang.Integer sampleRate;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$AudioDetails mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer audioChannelCount;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$AudioDetails clone();
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector$ImageDetails {
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$ImageDetails mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$ImageDetails clone();
-  int cachedSize;
-  java.lang.Boolean usedMonoFilename;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$Resolution resolution;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$ImageDetails clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector$ImagePlaybackDetails {
-  int cachedSize;
-  java.lang.Integer playbackMode;
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$ImagePlaybackDetails mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$ImagePlaybackDetails clear();
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$ImagePlaybackDetails clone();
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector$MediaDetails {
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$MediaDetails mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int checkAudioCodecOrThrow(int);
-  int checkVideoCodecOrThrow(int);
-  int cachedSize;
-  java.lang.String fileExtension;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$ImageDetails imageDetails;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$MediaDetails clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$VideoDetails videoDetails;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$MediaDetails clone();
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$AudioDetails audioDetails;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector$PickerDetails {
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$PickerDetails mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-  java.lang.Integer numberOfFiles;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$PickerDetails clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer numberOfFolders;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$PickerDetails clone();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector$PlaybackDetails {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$PlaybackDetails clone();
-  int checkPlaybackModeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$PlaybackDetails mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$ImagePlaybackDetails imagePlayback;
-  int checkPlaybackEngineOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$PlaybackDetails clear();
-  java.lang.Long playbackDurationSeconds;
-  int cachedSize;
-  java.lang.Integer playbackEngine;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$VideoPlaybackDetails videoPlayback;
-  int checkPlaybackStateOrThrow(int);
-   <init>();
-  java.lang.Integer playbackState;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector$Resolution {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$Resolution mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-   <init>();
-  java.lang.Integer width;
-  java.lang.Integer height;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$Resolution clear();
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$Resolution clone();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector$SphericalMetadata {
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$SphericalMetadata mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-  int checkProjectionTypeOrThrow(int);
-  java.lang.Integer metadataVersion;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Integer meshCrc;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$SphericalMetadata clone();
-   <init>();
-  java.lang.Integer projectionType;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$SphericalMetadata clear();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector$VideoDetails {
-  java.lang.Boolean usedWallyFilename;
-  java.lang.Boolean usedMonoFilename;
-  java.lang.Integer audioBitRate;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$SphericalMetadata sphericalMetadata;
-  java.lang.Integer videoCodec;
-  java.lang.Boolean usedWalleFilename;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$Resolution resolution;
-  java.lang.Integer audioChannelCount;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$VideoDetails mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$VideoDetails clear();
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Long mediaLengthSeconds;
-  java.lang.Double framesPerSecond;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$VideoDetails clone();
-  java.lang.Integer sampleRate;
-  int cachedSize;
-  java.lang.Integer audioCodec;
-  java.lang.Integer videoBitRate;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$JumpInspector$VideoPlaybackDetails {
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$VideoPlaybackDetails clear();
-  java.lang.Integer playbackMode;
-  java.lang.Boolean usedExternalSync;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$VideoPlaybackDetails mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$JumpInspector$VideoPlaybackDetails clone();
-  java.lang.Integer droppedFramesCount;
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Keyboard {
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardEvent[] keyboardEvents;
-  int checkKeyboardEventTypeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$Keyboard clear();
-  int checkKeyboardTextTypeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$Keyboard clone();
-  int checkKeyboardInputTypeOrThrow(int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Keyboard mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardEvent {
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$Application keyboardService;
-  com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardEvent mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardEvent[] _emptyArray;
-  com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardEvent[] emptyArray();
-  com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardEvent clone();
-  com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardEvent clear();
-  java.lang.Long clientTimestamp;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardTextEntry textEntry;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.String[] enabledLanguages;
-  java.lang.String[] voiceInputLanguages;
-  java.lang.Integer suggestionCount;
-  java.lang.String layout;
-  java.lang.Integer inputType;
-   <init>();
-  java.lang.String[] systemLanguages;
-  java.lang.Integer eventType;
-  java.lang.String language;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardTextEntry {
-  com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardTextEntry clone();
-  java.lang.String layout;
-  int cachedSize;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Integer length;
-  java.lang.String language;
-  java.lang.Integer type;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardTextEntry mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Keyboard$KeyboardTextEntry clear();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Launcher {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Launcher mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int checkNavItemOrThrow(int);
-  java.lang.Integer navItem;
-  com.google.common.logging.nano.Vr$VREvent$Launcher clone();
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$Launcher clear();
-  int cachedSize;
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Lullaby {
-  com.google.common.logging.nano.Vr$VREvent$Lullaby clone();
-  com.google.common.logging.nano.Vr$VREvent$Lullaby mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Lullaby clear();
-  java.lang.String contentId;
-  int cachedSize;
-  int checkUiElementOrThrow(int);
-  java.lang.Integer uiElement;
-  com.google.common.logging.nano.Vr$VREvent$Lullaby$LoadTime loadTime;
-  java.lang.Integer index;
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Lullaby$LoadTime {
-  com.google.common.logging.nano.Vr$VREvent$Lullaby$LoadTime clone();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Lullaby$LoadTime clear();
-  java.lang.Integer assetType;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int checkAssetTypeOrThrow(int);
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Lullaby$LoadTime mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Long loadTimeMs;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$PerformanceStats {
-  int cachedSize;
-   <init>();
-  float[] gpuThrottlingTemperature;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] scanlineRacingVsyncOvershootUs;
-  com.google.common.logging.nano.Vr$VREvent$PerformanceStats mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Float shutdownSkinTemperatureCelsius;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] totalRenderTime;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] presentTime;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] appRenderTime;
-  float[] cpuThrottlingTemperature;
-  java.lang.Integer averageFps;
-  java.lang.Float averageAppFps;
-  java.lang.Float throttleSkinTemperatureCelsius;
-  com.google.common.logging.nano.Vr$VREvent$TimeSeriesData timeSeriesData;
-  java.lang.Float vrMaxSkinTemperatureCelsius;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] frameTime;
-  com.google.common.logging.nano.Vr$VREvent$PerformanceStats clone();
-  java.lang.Integer memoryConsumptionKilobytes;
-  float[] gpuShutdownTemperature;
-  com.google.common.logging.nano.Vr$VREvent$PerformanceStats clear();
-  java.lang.Integer thermalEventFlags;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] postFrameTime;
-  java.lang.Float edsFps;
-  float[] cpuShutdownTemperature;
-  float[] batteryThrottlingTemperature;
-  com.google.common.logging.nano.Vr$VREvent$HistogramBucket[] consecutiveDroppedFrames;
-  float[] batteryShutdownTemperature;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$PhoneAlignment {
-  com.google.common.logging.nano.Vr$VREvent$PhoneAlignment clone();
-  com.google.common.logging.nano.Vr$VREvent$PhoneAlignment mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Vector2 lensOffset;
-  java.lang.Float angleDegrees;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Vector2[] touchLocations;
-  com.google.common.logging.nano.Vr$VREvent$PhoneAlignment clear();
-  int cachedSize;
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Photos {
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Photos clone();
-  com.google.common.logging.nano.Vr$VREvent$Photos clear();
-  java.lang.Integer numPhotos;
-  com.google.common.logging.nano.Vr$VREvent$Photos mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Photos$OpenMedia openMedia;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Photos$WarmWelcome warmWelcome;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Photos$OpenMedia {
-  int checkMediaSourceOrThrow(int);
-  java.lang.Integer type;
-   <init>();
-  java.lang.Integer source;
-  com.google.common.logging.nano.Vr$VREvent$Photos$OpenMedia mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Boolean isSample;
-  com.google.common.logging.nano.Vr$VREvent$Photos$OpenMedia clone();
-  int cachedSize;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$Photos$OpenMedia clear();
-  int checkMediaTypeOrThrow(int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Photos$WarmWelcome {
-  com.google.common.logging.nano.Vr$VREvent$Photos$WarmWelcome mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Photos$WarmWelcome clone();
-  java.lang.Float exitProgress;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Photos$WarmWelcome clear();
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$QrCodeScan {
-  int cachedSize;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  int checkStatusOrThrow(int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$QrCodeScan clear();
-  java.lang.Integer status;
-  java.lang.String headMountConfigUrl;
-  com.google.common.logging.nano.Vr$VREvent$QrCodeScan clone();
-  com.google.common.logging.nano.Vr$VREvent$QrCodeScan mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Renderer {
-  java.lang.String glRenderer;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Renderer clone();
-  java.lang.String glVersion;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Renderer clear();
-  java.lang.String glVendor;
-  com.google.common.logging.nano.Vr$VREvent$Renderer mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams {
-  java.lang.Boolean disallowMultiview;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Boolean touchOverlayEnabled;
-  java.lang.Boolean useOnlineMagnetometerCalibration;
-   <init>();
-  java.lang.Boolean useSystemClockForSensorTimestamps;
-  java.lang.Boolean allowDynamicLibraryLoading;
-  java.lang.Boolean enableForcedTrackingCompat;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$ScreenCaptureConfig screenCaptureConfig;
-  java.lang.Boolean useDeviceIdleDetection;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$AsyncReprojectionConfig asyncReprojectionConfig;
-  java.lang.Integer daydreamImageAlignment;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$PerformanceOverlayInfo performanceOverlayInfo;
-  java.lang.Boolean daydreamImageAlignmentEnabled;
-  java.lang.Boolean useMagnetometerInSensorFusion;
-  java.lang.Boolean useDirectModeSensors;
-  java.lang.Boolean useStationaryBiasCorrection;
-  java.lang.Boolean cpuLateLatchingEnabled;
-  java.lang.Boolean allowVrcoreHeadTracking;
-  int checkDaydreamImageAlignmentOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams clear();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams clone();
-  java.lang.Boolean allowDynamicJavaLibraryLoading;
-  java.lang.Boolean allowVrcoreCompositing;
-  java.lang.Boolean dimUiLayer;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$AsyncReprojectionConfig {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Long stripsPerFrame;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$AsyncReprojectionConfig mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$AsyncReprojectionConfig clone();
-  int cachedSize;
-  java.lang.Long flags;
-  java.lang.Long blackBoost;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$AsyncReprojectionConfig clear();
-   <init>();
-  java.lang.Long vsyncGracePeriodMicros;
-  java.lang.Long displayLatencyMicros;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$PerformanceOverlayInfo {
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$PerformanceOverlayInfo mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-   <init>();
-  java.lang.String version;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$PerformanceOverlayInfo clear();
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$PerformanceOverlayInfo clone();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$ScreenCaptureConfig {
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$ScreenCaptureConfig clone();
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$ScreenCaptureConfig clear();
-  java.lang.Boolean allowScreenRecord;
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams$ScreenCaptureConfig mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Boolean allowCasting;
-  java.lang.Boolean allowScreenshot;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$SensorStats {
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$SensorStats clear();
-  com.google.common.logging.nano.Vr$VREvent$SensorStats clone();
-  com.google.common.logging.nano.Vr$VREvent$SensorStats mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$GyroscopeStats gyroscopeStats;
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$SensorStats$GyroscopeStats {
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$Vector3 bias;
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$Vector3 lowerBound;
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$GyroscopeStats clear();
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$GyroscopeStats mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$Vector3 standardDeviation;
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$Vector3 upperBound;
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$GyroscopeStats clone();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$SensorStats$Vector3 {
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Float z;
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$Vector3 mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$Vector3 clone();
-  java.lang.Float y;
-  java.lang.Float x;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$SensorStats$Vector3 clear();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$HeadSetOnOffStats onOffStats;
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$PowerState powerState;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset clear();
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset clone();
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$MemoryStats memoryStats;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$HeadSetOnOffStats {
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$HeadSetOnOffStats clone();
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$HeadSetOnOffStats mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Long onOffCount;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$HeadSetOnOffStats clear();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$MemoryStats {
-  java.lang.Long timeSinceBootNs;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$MemoryStats clear();
-   <init>();
-  java.lang.Long totalMemoryKb;
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$MemoryStats clone();
-  java.lang.Long availableMemoryKb;
-  java.lang.Long freeMemoryKb;
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$MemoryStats mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$PowerState {
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  int checkPowerStatesOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$PowerState clear();
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$PowerState clone();
-  com.google.common.logging.nano.Vr$VREvent$StandaloneHeadset$PowerState mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer powerStates;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-   <init>();
-  java.lang.Long powerStateDurationNs;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$StreetView {
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$StreetView$TutorialSession tutorialSession;
-  com.google.common.logging.nano.Vr$VREvent$StreetView clear();
-  com.google.common.logging.nano.Vr$VREvent$StreetView$PanoSession panoSession;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$StreetView mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$StreetView clone();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$StreetView$PanoSession {
-  java.lang.Integer playPauseClicks;
-  com.google.common.logging.nano.Vr$VREvent$StreetView$PanoSession clear();
-  java.lang.Integer infoClicks;
-  int cachedSize;
-  int checkSourceOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$StreetView$PanoSession clone();
-  com.google.common.logging.nano.Vr$VREvent$StreetView$PanoSession mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer nodesNavigated;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer panosAvailable;
-  java.lang.Integer source;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Integer nextClicks;
-  java.lang.Integer panosViewed;
-  java.lang.Integer prevClicks;
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$StreetView$TutorialSession {
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  int checkTutorialOrThrow(int);
-  java.lang.Integer tutorial;
-  java.lang.Boolean completed;
-  com.google.common.logging.nano.Vr$VREvent$StreetView$TutorialSession clear();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$StreetView$TutorialSession mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$StreetView$TutorialSession clone();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$TimeSeriesData {
-  com.google.common.logging.nano.Vr$VREvent$TimeSeriesData clone();
-  com.google.common.logging.nano.Vr$VREvent$TimeSeriesData mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer timeIntervalSeconds;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$TimeSeriesData clear();
-  com.google.common.logging.nano.Vr$VREvent$TimeSeriesData$TimeIntervalData[] timeIntervalData;
-  int cachedSize;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$TimeSeriesData$TimeIntervalData {
-  com.google.common.logging.nano.Vr$VREvent$TimeSeriesData$TimeIntervalData[] emptyArray();
-  float[] cpuTemperature;
-  com.google.common.logging.nano.Vr$VREvent$TimeSeriesData$TimeIntervalData[] _emptyArray;
-  com.google.common.logging.nano.Vr$VREvent$TimeSeriesData$TimeIntervalData mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$TimeSeriesData$TimeIntervalData clone();
-  int cachedSize;
-  java.lang.Integer thermalWarningsShown;
-  java.lang.Integer batteryLevel;
-  float[] batteryTemperature;
-  java.lang.Integer edsThreadFrameDropCount;
-  com.google.common.logging.nano.Vr$VREvent$TimeSeriesData$TimeIntervalData clear();
-   <init>();
-  java.lang.Integer batteryLevelDelta;
-  java.lang.Float skinTemperature;
-  float[] gpuTemperature;
-  java.lang.Integer intervalStartTimeSeconds;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Transform {
-  java.lang.Float translationX;
-  java.lang.Float rotationQy;
-   <init>();
-  java.lang.Float rotationQx;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Float translationZ;
-  com.google.common.logging.nano.Vr$VREvent$Transform clone();
-  java.lang.Float rotationQz;
-  java.lang.Float translationY;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Transform clear();
-  java.lang.Float scale;
-  com.google.common.logging.nano.Vr$VREvent$Transform mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$Vector2 {
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$Vector2 clone();
-  java.lang.Float x;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Vector2 clear();
-  com.google.common.logging.nano.Vr$VREvent$Vector2 mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Float y;
-  com.google.common.logging.nano.Vr$VREvent$Vector2[] _emptyArray;
-  com.google.common.logging.nano.Vr$VREvent$Vector2[] emptyArray();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrCore {
-  com.google.common.logging.nano.Vr$VREvent$VrCore$Controller controller;
-  com.google.common.logging.nano.Vr$VREvent$VrCore clone();
-  int checkPermissionOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$VrCore$LockScreenEvent lockScreenEvent;
-  java.lang.Integer permission;
-  java.lang.Integer clientApiVersion;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$VrCore$DashboardEvent dashboardEvent;
-  int cachedSize;
-   <init>();
-  java.lang.Integer controllerHandedness;
-  com.google.common.logging.nano.Vr$VREvent$VrCore clear();
-  com.google.common.logging.nano.Vr$VREvent$VrCore$CaptureEvent captureEvent;
-  java.lang.Long vrSessionId;
-  com.google.common.logging.nano.Vr$VREvent$VrCore mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$Application foregroundApplication;
-  java.lang.Boolean isInDemoMode;
-  com.google.common.logging.nano.Vr$VREvent$Application previousForegroundApplication;
-  java.lang.Integer errorCode;
-  int checkErrorCodeOrThrow(int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrCore$CaptureEvent {
-  com.google.common.logging.nano.Vr$VREvent$VrCore$CaptureEvent mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Boolean initiatedByController;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$VrCore$CaptureEvent clone();
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$VrCore$CaptureEvent clear();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrCore$Controller {
-  java.lang.String softwareRevision;
-  int checkSensorTypeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$VrCore$Controller mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Integer axis;
-  java.lang.String hardwareRevision;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$VrCore$Controller clone();
-  java.lang.String manufacturer;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Integer sampleCount;
-  java.lang.String model;
-  java.lang.Integer otaRetries;
-  java.lang.Integer xRailCount;
-  java.lang.Integer batteryLevel;
-  java.lang.String firmware;
-  java.lang.Boolean isConnected;
-  java.lang.Integer yRailCount;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$VrCore$Controller clear();
-  java.lang.Integer status;
-  int checkControllerAxisOrThrow(int);
-  java.lang.Integer zRailCount;
-  java.lang.Integer sensorType;
-  java.lang.Integer totalControllerLagCount;
-  java.lang.String availableFirmware;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrCore$DashboardEvent {
-  com.google.common.logging.nano.Vr$VREvent$VrCore$DashboardEvent clear();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$Application worldApp;
-  logs.proto.wireless.performance.mobile.nano.MemoryMetric$AndroidMemoryStats worldAppMemoryStats;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.common.logging.nano.Vr$VREvent$VrCore$DashboardEvent$DashboardDismissDetails dismissDetails;
-  int checkDashboardEventTypeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$VrCore$DashboardEvent clone();
-  java.lang.Integer eventType;
-  java.lang.Long clientTimestamp;
-  java.lang.String sessionId;
-  com.google.common.logging.nano.Vr$VREvent$VrCore$DashboardEvent mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrCore$DashboardEvent$DashboardDismissDetails {
-  com.google.common.logging.nano.Vr$VREvent$VrCore$DashboardEvent$DashboardDismissDetails mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Boolean worldAppDied;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Integer dismissReason;
-  int checkDashboardDismissReasonOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$VrCore$DashboardEvent$DashboardDismissDetails clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$VrCore$DashboardEvent$DashboardDismissDetails clone();
-  int cachedSize;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrCore$LockScreenEvent {
-  int checkLockScreenEventTypeOrThrow(int);
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$VrCore$LockScreenEvent mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$VrCore$LockScreenEvent clone();
-  com.google.common.logging.nano.Vr$VREvent$VrCore$LockScreenEvent clear();
-   <init>();
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer eventType;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrHome {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$VrHome$DialogAction dialogAction;
-  com.google.common.logging.nano.Vr$VREvent$VrHome clone();
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup setup;
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$VrHome clear();
-  com.google.common.logging.nano.Vr$VREvent$GConfigUpdate gConfigUpdate;
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$VrHome mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$VrHome$GetViewerClick getViewerClick;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrHome$DialogAction {
-  com.google.common.logging.nano.Vr$VREvent$VrHome$DialogAction clear();
-  com.google.common.logging.nano.Vr$VREvent$VrHome$DialogAction mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer actionType;
-   <init>();
-  int cachedSize;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  int checkDialogTypeOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$VrHome$DialogAction clone();
-  java.lang.Integer type;
-  int checkDialogActionTypeOrThrow(int);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrHome$GetViewerClick {
-  com.google.common.logging.nano.Vr$VREvent$VrHome$GetViewerClick clone();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$VrHome$GetViewerClick mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  java.lang.String url;
-  com.google.common.logging.nano.Vr$VREvent$VrHome$GetViewerClick clear();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrHome$Setup {
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup$View view;
-  int checkStepOrThrow(int);
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup clone();
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup$StepStateChange stepStateChange;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup clear();
-   <init>();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrHome$Setup$StepStateChange {
-  java.lang.Integer newStepState;
-  int checkStepStateOrThrow(int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-   <init>();
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup$StepStateChange clone();
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup$StepStateChange mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup$StepStateChange clear();
-  java.lang.Integer step;
-  java.lang.Integer previousStepState;
-  int cachedSize;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrHome$Setup$View {
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup$View mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer step;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.Integer page;
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup$View clear();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$VrHome$Setup$View clone();
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrStreaming {
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming$Frame[] frame;
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming clear();
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming clone();
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming$SessionInfo sessionInfo;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrStreaming$Frame {
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming$Frame clear();
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming$Frame[] emptyArray();
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming$Frame[] _emptyArray;
-  java.lang.Long poseSendTimeUsec;
-  java.lang.Long decodeStartTimeUsec;
-  java.lang.Integer poseId;
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming$Frame mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.Long decodeEndTimeUsec;
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming$Frame clone();
-   <init>();
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Long framePresentTimeUsec;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.Vr$VREvent$VrStreaming$SessionInfo {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  java.lang.String sessionId;
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming$SessionInfo clear();
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming$SessionInfo clone();
-  int cachedSize;
-  com.google.common.logging.nano.Vr$VREvent$VrStreaming$SessionInfo mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.VrBaseOuterClass$VrBase {
-  com.google.common.logging.nano.VrBaseOuterClass$VrBase mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.common.logging.nano.VrBaseOuterClass$VrBase clone();
-  int cachedSize;
-  com.google.common.logging.nano.VrBaseOuterClass$VrBase clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.common.logging.nano.VrBaseOuterClass$VrBase$HeadMount {
-  com.google.common.logging.nano.VrBaseOuterClass$VrBase$HeadMount clone();
-  com.google.common.logging.nano.VrBaseOuterClass$VrBase$HeadMount mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-   <init>();
-  com.google.common.logging.nano.VrBaseOuterClass$VrBase$HeadMount clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.String model;
-  java.lang.String vendor;
-}
-
--keep,allowobfuscation class com.google.devtools.build.android.desugar.runtime.ThrowableExtension {
-  boolean useMimicStrategy();
-  com.google.devtools.build.android.desugar.runtime.ThrowableExtension$AbstractDesugaringStrategy STRATEGY;
-  void addSuppressed(java.lang.Throwable, java.lang.Throwable);
-  int API_LEVEL;
-  java.lang.Integer readApiLevelFromBuildVersion();
-}
-
--keep,allowobfuscation class com.google.devtools.build.android.desugar.runtime.ThrowableExtension$AbstractDesugaringStrategy {
-  void printStackTrace(java.lang.Throwable, java.io.PrintStream);
-  void addSuppressed(java.lang.Throwable, java.lang.Throwable);
-  void printStackTrace(java.lang.Throwable, java.io.PrintWriter);
-  void printStackTrace(java.lang.Throwable);
-  java.lang.Throwable[] getSuppressed(java.lang.Throwable);
-  java.lang.Throwable[] EMPTY_THROWABLE_ARRAY;
-   <init>();
-}
-
--keep,allowobfuscation class com.google.devtools.build.android.desugar.runtime.ThrowableExtension$ConcurrentWeakIdentityHashMap {
-  java.lang.ref.ReferenceQueue referenceQueue;
-  void deleteEmptyKeys();
-   <init>();
-  java.util.concurrent.ConcurrentHashMap map;
-  java.util.List get(java.lang.Throwable, boolean);
-}
-
--keep,allowobfuscation class com.google.devtools.build.android.desugar.runtime.ThrowableExtension$ConcurrentWeakIdentityHashMap$WeakKey {
-  java.lang.Object get();
-  int hash;
-   <init>(java.lang.Throwable, java.lang.ref.ReferenceQueue);
-}
-
--keep,allowobfuscation class com.google.devtools.build.android.desugar.runtime.ThrowableExtension$MimicDesugaringStrategy {
-  java.lang.Throwable[] EMPTY_THROWABLE_ARRAY;
-   <init>();
-  com.google.devtools.build.android.desugar.runtime.ThrowableExtension$ConcurrentWeakIdentityHashMap map;
-}
-
--keep,allowobfuscation class com.google.devtools.build.android.desugar.runtime.ThrowableExtension$NullDesugaringStrategy {
-   <init>();
-  java.lang.Throwable[] EMPTY_THROWABLE_ARRAY;
-}
-
--keep,allowobfuscation class com.google.devtools.build.android.desugar.runtime.ThrowableExtension$ReuseDesugaringStrategy {
-   <init>();
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.CodedInputByteBufferNano {
-  boolean readBool();
-  long readRawLittleEndian64();
-  byte[] getData(int, int);
-  long readUInt64();
-  void popLimit(int);
-  void skipRawBytes(int);
-  void skipMessage();
-  long readSFixed64();
-  boolean skipField(int);
-  long readSInt64();
-  int readInt32();
-  int lastTag;
-  byte readRawByte();
-  long readRawVarint64();
-  int getBytesUntilLimit();
-  boolean isAtEnd();
-  float readFloat();
-  void checkLastTagWas(int);
-  int recursionLimit;
-  int bufferSizeAfterLimit;
-  int bufferSize;
-  byte[] buffer;
-  int readEnum();
-  int bufferStart;
-  int sizeLimit;
-  java.lang.String readString();
-  com.google.protobuf.nano.CodedInputByteBufferNano newInstance(byte[]);
-  int readRawVarint32();
-  void rewindToPosition(int);
-   <init>(byte[], int, int);
-  int getPosition();
-  void readGroup(com.google.protobuf.nano.MessageNano, int);
-  int recursionDepth;
-  void readMessage(com.google.protobuf.nano.MessageNano);
-  long readInt64();
-  int readSFixed32();
-  int readSInt32();
-  int readUInt32();
-  int readRawLittleEndian32();
-  long decodeZigZag64(long);
-  com.google.protobuf.nano.CodedInputByteBufferNano newInstance(byte[], int, int);
-  int bufferPos;
-  double readDouble();
-  int currentLimit;
-  int decodeZigZag32(int);
-  long readFixed64();
-  byte[] readBytes();
-  int pushLimit(int);
-  void recomputeBufferSizeAfterLimit();
-  int readFixed32();
-  int readTag();
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.CodedOutputByteBufferNano {
-  int computeInt64SizeNoTag(long);
-  int computeSInt64SizeNoTag(long);
-  void writeDoubleNoTag(double);
-  void writeSFixed64NoTag(long);
-  void writeMessage(int, com.google.protobuf.nano.MessageNano);
-  int computeSFixed64SizeNoTag(long);
-  int encodedLengthGeneral(java.lang.CharSequence, int);
-  int computeSFixed32Size(int, int);
-  int computeUInt32SizeNoTag(int);
-  void writeFixed64NoTag(long);
-  void writeUInt64(int, long);
-  void writeInt32NoTag(int);
-  void writeRawByte(int);
-  void writeFloatNoTag(float);
-  int computeMessageSizeNoTag(com.google.protobuf.nano.MessageNano);
-  int computeInt32Size(int, int);
-  int computeUInt64Size(int, long);
-  void writeRawVarint64(long);
-  int computeSInt64Size(int, long);
-  int encodedLength(java.lang.CharSequence);
-  void writeInt64NoTag(long);
-  int computeFloatSizeNoTag(float);
-  void writeUInt32NoTag(int);
-  void writeFloat(int, float);
-  int computeBytesSize(int, byte[]);
-  void writeGroupNoTag(com.google.protobuf.nano.MessageNano);
-  int computeEnumSizeNoTag(int);
-  int computeMessageSize(int, com.google.protobuf.nano.MessageNano);
-  int computeStringSize(int, java.lang.String);
-  void encodeDirect(java.lang.CharSequence, java.nio.ByteBuffer);
-  int computeEnumSize(int, int);
-   <init>(java.nio.ByteBuffer);
-  int computeFixed64Size(int, long);
-  void encode(java.lang.CharSequence, java.nio.ByteBuffer);
-  void writeInt64(int, long);
-  void writeSInt32NoTag(int);
-  void writeSFixed32NoTag(int);
-  int computeSInt32SizeNoTag(int);
-  void checkNoSpaceLeft();
-  int computeUInt64SizeNoTag(long);
-  void writeBoolNoTag(boolean);
-  void writeFixed32NoTag(int);
-  void writeStringNoTag(java.lang.String);
-  int computeBoolSizeNoTag(boolean);
-  int computeBytesSizeNoTag(byte[]);
-   <init>(byte[], int, int);
-  int computeStringSizeNoTag(java.lang.String);
-  int computeDoubleSizeNoTag(double);
-  com.google.protobuf.nano.CodedOutputByteBufferNano newInstance(byte[], int, int);
-  int computeGroupSize(int, com.google.protobuf.nano.MessageNano);
-  int computeUInt32Size(int, int);
-  int encodeZigZag32(int);
-  long encodeZigZag64(long);
-  void writeRawBytes(byte[]);
-  int computeRawVarint32Size(int);
-  int computeSFixed32SizeNoTag(int);
-  int computeSFixed64Size(int, long);
-  void writeRawByte(byte);
-  void writeRawLittleEndian64(long);
-  void writeBool(int, boolean);
-  int computeSInt32Size(int, int);
-  java.nio.ByteBuffer buffer;
-  int encode(java.lang.CharSequence, byte[], int, int);
-  int computeTagSize(int);
-  int computeFixed32SizeNoTag(int);
-  int computeGroupSizeNoTag(com.google.protobuf.nano.MessageNano);
-  int computeFixed32Size(int, int);
-  void writeRawLittleEndian32(int);
-  void writeBytesNoTag(byte[], int, int);
-  void writeMessageNoTag(com.google.protobuf.nano.MessageNano);
-  int spaceLeft();
-  void writeString(int, java.lang.String);
-  int computeBytesSizeNoTag(int);
-  void writeSInt64NoTag(long);
-  void writeRawBytes(byte[], int, int);
-  int computeDoubleSize(int, double);
-  void writeInt32(int, int);
-  void writeRawVarint32(int);
-  void writeDouble(int, double);
-  int computeInt64Size(int, long);
-  int computeFloatSize(int, float);
-  com.google.protobuf.nano.CodedOutputByteBufferNano newInstance(byte[]);
-  void writeTag(int, int);
-  int computeBoolSize(int, boolean);
-  void writeUInt64NoTag(long);
-  int computeInt32SizeNoTag(int);
-  void writeBytesNoTag(byte[]);
-  void writeEnumNoTag(int);
-  int computeFixed64SizeNoTag(long);
-  int computeRawVarint64Size(long);
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.CodedOutputByteBufferNano$OutOfSpaceException {
-   <init>(int, int);
-  java.lang.Throwable initCause(java.lang.Throwable);
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.ExtendableMessageNano {
-  int computeSerializedSize();
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.protobuf.nano.ExtendableMessageNano clone();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.Extension {
-  java.lang.Object getRepeatedValueFrom(java.util.List);
-  void writeTo(java.lang.Object, com.google.protobuf.nano.CodedOutputByteBufferNano);
-  void readDataInto(com.google.protobuf.nano.UnknownFieldData, java.util.List);
-  int type;
-  boolean repeated;
-  int computeSerializedSize(java.lang.Object);
-  int computeRepeatedSerializedSize(java.lang.Object);
-  java.lang.Object getSingularValueFrom(java.util.List);
-  java.lang.Class clazz;
-  void writeRepeatedData(java.lang.Object, com.google.protobuf.nano.CodedOutputByteBufferNano);
-   <init>(int, java.lang.Class, int, boolean);
-  int computeSingularSerializedSize(java.lang.Object);
-  void writeSingularData(java.lang.Object, com.google.protobuf.nano.CodedOutputByteBufferNano);
-  java.lang.Object readData(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int tag;
-   <init>(int, java.lang.Class, int, boolean, com.google.protobuf.nano.Extension$1);
-  java.lang.Object getValueFrom(java.util.List);
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.Extension$PrimitiveExtension {
-  int type;
-  java.lang.Object readData(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int nonPackedTag;
-  int tag;
-   <init>(int, java.lang.Class, int, boolean, int, int);
-  int packedTag;
-  int computePackedDataSize(java.lang.Object);
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.FieldArray {
-  com.google.protobuf.nano.FieldData dataAt(int);
-  com.google.protobuf.nano.FieldData DELETED;
-   <init>(int);
-  void remove(int);
-  boolean mGarbage;
-  int mSize;
-  com.google.protobuf.nano.FieldArray clone();
-  int[] mFieldNumbers;
-  int idealByteArraySize(int);
-  void put(int, com.google.protobuf.nano.FieldData);
-  int idealIntArraySize(int);
-  boolean arrayEquals(com.google.protobuf.nano.FieldData[], com.google.protobuf.nano.FieldData[], int);
-  boolean isEmpty();
-  int size();
-   <init>();
-  int binarySearch(int);
-  com.google.protobuf.nano.FieldData[] mData;
-  void gc();
-  boolean arrayEquals(int[], int[], int);
-  com.google.protobuf.nano.FieldData get(int);
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.FieldData {
-  byte[] toByteArray();
-  boolean equals(java.lang.Object);
-  void addUnknownField(com.google.protobuf.nano.UnknownFieldData);
-  java.lang.Object value;
-  void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano);
-  void setValue(com.google.protobuf.nano.Extension, java.lang.Object);
-  int computeSerializedSize();
-   <init>(com.google.protobuf.nano.Extension, java.lang.Object);
-  com.google.protobuf.nano.FieldData clone();
-  int hashCode();
-  java.util.List unknownFieldData;
-  java.lang.Object getValue(com.google.protobuf.nano.Extension);
-   <init>();
-  com.google.protobuf.nano.Extension cachedExtension;
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.InternalNano {
-  java.lang.Object LAZY_INIT_LOCK;
-  void cloneUnknownFieldData(com.google.protobuf.nano.ExtendableMessageNano, com.google.protobuf.nano.ExtendableMessageNano);
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.InvalidProtocolBufferNanoException {
-  com.google.protobuf.nano.InvalidProtocolBufferNanoException malformedVarint();
-   <init>(java.lang.String);
-  com.google.protobuf.nano.InvalidProtocolBufferNanoException recursionLimitExceeded();
-  com.google.protobuf.nano.InvalidProtocolBufferNanoException invalidWireType();
-  com.google.protobuf.nano.InvalidProtocolBufferNanoException negativeSize();
-  com.google.protobuf.nano.InvalidProtocolBufferNanoException invalidTag();
-  com.google.protobuf.nano.InvalidProtocolBufferNanoException invalidEndTag();
-  com.google.protobuf.nano.InvalidProtocolBufferNanoException truncatedMessage();
-  java.lang.String toString();
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.MessageNano {
-   <init>();
-  void toByteArray(com.google.protobuf.nano.MessageNano, byte[], int, int);
-  byte[] toByteArray(com.google.protobuf.nano.MessageNano);
-  void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano);
-  com.google.protobuf.nano.MessageNano mergeFrom(com.google.protobuf.nano.MessageNano, byte[], int, int);
-  int computeSerializedSize();
-  boolean messageNanoEquals(com.google.protobuf.nano.MessageNano, com.google.protobuf.nano.MessageNano);
-  int getCachedSize();
-  com.google.protobuf.nano.MessageNano mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-  com.google.protobuf.nano.MessageNano clone();
-  int getSerializedSize();
-  com.google.protobuf.nano.MessageNano mergeFrom(com.google.protobuf.nano.MessageNano, byte[]);
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.MessageNanoPrinter {
-  java.lang.String deCamelCaseify(java.lang.String);
-  java.lang.String sanitizeString(java.lang.String);
-  void print(java.lang.String, java.lang.Object, java.lang.StringBuffer, java.lang.StringBuffer);
-  java.lang.String escapeString(java.lang.String);
-  java.lang.String print(com.google.protobuf.nano.MessageNano);
-  void appendQuotedBytes(byte[], java.lang.StringBuffer);
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.UnknownFieldData {
-  byte[] bytes;
-  void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano);
-  int tag;
-   <init>(int, byte[]);
-  int computeSerializedSize();
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.WireFormatNano {
-  int getRepeatedFieldArrayLength(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  float[] EMPTY_FLOAT_ARRAY;
-  byte[] EMPTY_BYTES;
-  double[] EMPTY_DOUBLE_ARRAY;
-  boolean[] EMPTY_BOOLEAN_ARRAY;
-  int getTagFieldNumber(int);
-  java.lang.String[] EMPTY_STRING_ARRAY;
-  int getTagWireType(int);
-  long[] EMPTY_LONG_ARRAY;
-  int[] EMPTY_INT_ARRAY;
-  int makeTag(int, int);
-  byte[][] EMPTY_BYTES_ARRAY;
-}
-
--keep,allowobfuscation class com.google.protobuf.nano.android.ParcelableMessageNanoCreator {
-  com.google.protobuf.nano.MessageNano[] newArray(int);
-  void writeToParcel(java.lang.Class, com.google.protobuf.nano.MessageNano, android.os.Parcel);
-  java.lang.Class mClazz;
-  com.google.protobuf.nano.MessageNano createFromParcel(android.os.Parcel);
-}
-
--keep,allowobfuscation class com.google.vr.audio.DeviceInfo {
-  android.content.Context context;
-  void nativeUpdateHeadphoneStateChange(long, int);
-  android.content.BroadcastReceiver headphoneStateReceiver;
-  long access$000(com.google.vr.audio.DeviceInfo);
-  void access$100(com.google.vr.audio.DeviceInfo, long, int);
-  long nativeObject;
-   <init>(long, android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.audio.DeviceInfo$1 {
-   <init>(com.google.vr.audio.DeviceInfo);
-  com.google.vr.audio.DeviceInfo this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.AndroidNCompat {
-  void setVrThread(int);
-  boolean handleVrCoreAbsence(android.content.Context, int);
-  java.lang.String TAG;
-  int checkForVrCorePresence(android.content.Context);
-  boolean setVrModeEnabled(android.app.Activity, boolean);
-  boolean isVrModeSupported(android.content.Context);
-  void showWarningDialog(android.content.Context, int, int, android.content.DialogInterface$OnClickListener);
-  boolean setSustainedPerformanceMode(android.app.Activity, boolean);
-  boolean isVrModeHighPerformanceSupported(android.content.Context);
-  boolean setVrModeEnabled(android.app.Activity, boolean, int);
-  boolean isAtLeastNMR1();
-  java.lang.String access$000();
-  boolean isAtLeastN();
-  int sSdkLevelOverride;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.AndroidNCompat$1 {
-   <init>(android.content.Context);
-  android.content.Context val$context;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.AndroidNCompat$2 {
-   <init>(android.content.Context);
-  android.content.Context val$context;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.AndroidNCompat$3 {
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.CardboardGLSurfaceView {
-  java.util.ArrayList eventQueueWhileDetached;
-  boolean isRendererSet;
-  com.google.vr.cardboard.CardboardGLSurfaceView$DetachListener listener;
-  com.google.vr.cardboard.EglFactory eglFactory;
-  void setEGLWindowSurfaceFactory(android.opengl.GLSurfaceView$EGLWindowSurfaceFactory);
-  void setEGLContextFactory(android.opengl.GLSurfaceView$EGLContextFactory);
-  boolean isDetached;
-  java.lang.String TAG;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.CardboardGLSurfaceView$DetachListener {
-  void onSurfaceViewDetachedFromWindow();
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ConfigUtils {
-  boolean removeDeviceParamsFromExternalStorage();
-  com.google.protobuf.nano.MessageNano readFromInputStream(java.lang.Class, java.io.InputStream, int);
-  java.lang.String TAG;
-  com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams readDeviceParamsFromExternalStorage();
-  boolean writeToOutputStream(com.google.protobuf.nano.MessageNano, java.io.OutputStream, int);
-  com.google.protobuf.nano.MessageNano readFromExternalStorage(java.lang.Class, java.lang.String, int, boolean);
-  boolean writeToExternalStorage(com.google.protobuf.nano.MessageNano, java.lang.String, int);
-  boolean writeDisplayParamsToExternalStorage(com.google.vr.sdk.proto.nano.Display$DisplayParams);
-  boolean writeDeviceParamsToExternalStorage(com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams);
-  com.google.vr.sdk.proto.nano.Display$DisplayParams readDisplayParamsFromExternalStorage();
-  java.io.File getConfigFile(java.lang.String);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ContentProviderVrParamsProvider {
-  android.net.Uri sdkConfigurationParamsSettingUri;
-  com.google.protobuf.nano.MessageNano readParams(com.google.protobuf.nano.MessageNano, android.net.Uri, java.lang.String);
-  boolean writeParams(com.google.protobuf.nano.MessageNano, android.net.Uri);
-  android.net.Uri displayParamsSettingUri;
-  java.lang.String TAG;
-  android.content.ContentProviderClient client;
-  android.net.Uri userPrefsUri;
-   <init>(android.content.ContentProviderClient, java.lang.String);
-  android.net.Uri deviceParamsSettingUri;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ContextUtils {
-  android.app.Activity getActivity(android.content.Context);
-  android.content.ComponentName getComponentName(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.DisplaySynchronizer {
-  android.view.Display getDisplay();
-  void onConfigurationChanged();
-  android.view.Display display;
-  long lastDisplayRotationUpdateTimeNanos;
-  void shutdown();
-  void setDisplay(android.view.Display);
-  long nativeCreate(java.lang.ClassLoader, android.content.Context);
-  com.google.vr.cardboard.FrameMonitor frameMonitor;
-  void invalidateDisplayProperties();
-  void nativeUpdate(long, long, int);
-  void nativeOnMetricsChanged(long);
-  void nativeDestroy(long);
-  long DISPLAY_ROTATION_REFRESH_INTERVAL_NANOS;
-  long getNativeDisplaySynchronizer();
-  void onResume();
-  long nativeDisplaySynchronizer;
-  void checkNativeDisplaySynchronizer();
-   <init>(android.content.Context, android.view.Display);
-  android.util.DisplayMetrics displayMetrics;
-  int displayRotationDegrees;
-  void onPause();
-  void nativeReset(long, long, long);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.DisplayUtils {
-  android.view.Display getDefaultDisplay(android.content.Context);
-  boolean isSameDisplay(android.view.Display, android.view.Display);
-  android.util.DisplayMetrics getDisplayMetricsLandscape(android.view.Display);
-  float getMetersPerPixelFromDotsPerInch(float);
-  java.lang.String getExternalDisplayName(android.content.Context);
-  float getBorderSizeMeters(com.google.vr.sdk.proto.nano.Display$DisplayParams);
-  android.util.DisplayMetrics getDisplayMetricsLandscapeWithOverride(android.view.Display, com.google.vr.sdk.proto.nano.Display$DisplayParams);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.EglFactory {
-  void setEGLContextClientVersion(int);
-  boolean useDebug;
-   <init>();
-  void setUsePriorityContext(boolean);
-  boolean useProtected;
-  int eglContextClientVersion;
-  javax.microedition.khronos.egl.EGLContext sharedContext;
-  void setErrorReportingEnabled(boolean);
-  boolean usePriority;
-  void setUseDebug(boolean);
-  void setSharedContext(javax.microedition.khronos.egl.EGLContext);
-  boolean errorReportingEnabled;
-  boolean supportsProtectedContent(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay);
-  void setUseProtectedBuffers(boolean);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.EglReadyListener {
-  int glVersion;
-  void clearContext();
-  int getGLVersion();
-  javax.microedition.khronos.egl.EGLContext getEGLContext();
-  java.lang.Object listenerLock;
-  int parseVersionString(java.lang.String);
-  int eglContextFlags;
-  void releaseEventListener();
-  java.lang.Object contextInfoLock;
-   <init>();
-  com.google.vr.cardboard.EglReadyListener$EventListener listener;
-  int getEGLContextFlags();
-  void setEventListener(com.google.vr.cardboard.EglReadyListener$EventListener);
-  javax.microedition.khronos.egl.EGLContext eglContext;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.EglReadyListener$EventListener {
-  void onEglReady();
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager {
-  com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurfaceData surfaceData;
-  boolean isAttachedToGlContext;
-  int nextID;
-  void nativeUpdateSurface(long, int, int, long, float[]);
-   <init>(com.google.vr.cardboard.ExternalSurfaceManager$UpdateSurfaceCallback);
-  java.lang.Object surfaceDataUpdateLock;
-  int createExternalSurfaceImpl(int, int, com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurfaceCallback);
-  java.lang.String TAG;
-  com.google.vr.cardboard.ExternalSurfaceManager$UpdateSurfaceCallback updateSurfaceCallback;
-  void nativeCallback(long);
-  void access$000(long, int, int, long, float[]);
-  void access$200(long);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$1 {
-   <init>(long);
-  long val$nativeSurfaceManager;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$AndroidHandlerCallback {
-   <init>(java.lang.Runnable, java.lang.Runnable, android.os.Handler);
-  java.lang.Runnable surfaceListener;
-  java.lang.Runnable frameListener;
-  android.os.Handler handler;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurface {
-   <init>(int, int, int, com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurfaceCallback);
-  java.util.concurrent.atomic.AtomicBoolean hasNewFrame;
-  void maybeDetachFromCurrentGLContext();
-  int surfaceTextureWidth;
-  boolean isAttached;
-  void maybeAttachToCurrentGLContext(int);
-  java.util.concurrent.atomic.AtomicBoolean released;
-  java.lang.Object access$400(com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurface);
-  int surfaceTextureHeight;
-  java.lang.Object onFrameAvailableShutdownLock;
-  void shutdown(com.google.vr.cardboard.ExternalSurfaceManager$UpdateSurfaceCallback);
-  android.view.Surface getSurface();
-  float[] transformMatrix;
-  boolean access$500(com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurface);
-  java.util.concurrent.atomic.AtomicBoolean access$100(com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurface);
-  void maybeAttachToCurrentGLContext();
-  com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurfaceCallback callback;
-  void updateSurfaceTexture(com.google.vr.cardboard.ExternalSurfaceManager$UpdateSurfaceCallback);
-  int id;
-  android.graphics.SurfaceTexture surfaceTexture;
-  int[] glTextureId;
-  boolean isShutdown;
-  java.util.concurrent.atomic.AtomicBoolean access$300(com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurface);
-  com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurfaceCallback access$600(com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurface);
-  android.view.Surface surface;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurface$1 {
-  com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurface this$0;
-   <init>(com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurface);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurfaceCallback {
-  void cancelPosts();
-  void onSurfaceAvailable();
-  void onFrameAvailable();
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurfaceData {
-  java.util.HashMap surfacesToRelease;
-   <init>();
-   <init>(com.google.vr.cardboard.ExternalSurfaceManager$ExternalSurfaceData);
-  java.util.HashMap surfaces;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$NativeCallback {
-  android.os.Handler surfaceMainHandler;
-  long nativeFrameCallbackPtr;
-   <init>(long, long);
-  void lambda$new$0$ExternalSurfaceManager$NativeCallback(long);
-  java.lang.Runnable surfaceListener;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$NativeCallback$$Lambda$0 {
-  long arg$1;
-   <init>(long);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ExternalSurfaceManager$UpdateSurfaceCallback {
-  void updateSurface(int, int, long, float[]);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.FrameMonitor {
-  android.os.HandlerThread choreographerOwnerThread;
-  void shutdown();
-   <init>(android.view.Choreographer$FrameCallback);
-  void init();
-  void onResume();
-  android.view.Choreographer$FrameCallback callback;
-  java.lang.String TAG;
-  android.os.Handler handler;
-  void onPause();
-   <init>(android.view.Choreographer, android.view.Choreographer$FrameCallback);
-  android.view.Choreographer choreographer;
-  boolean isResumed;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.FullscreenMode {
-  void access$000(com.google.vr.cardboard.FullscreenMode);
-  android.view.Window window;
-  void setImmersiveStickyModeCompat();
-  void setFullscreenModeFlags();
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.FullscreenMode$1 {
-  com.google.vr.cardboard.FullscreenMode this$0;
-  android.os.Handler val$handler;
-   <init>(com.google.vr.cardboard.FullscreenMode, android.os.Handler);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.FullscreenMode$1$1 {
-  com.google.vr.cardboard.FullscreenMode$1 this$1;
-   <init>(com.google.vr.cardboard.FullscreenMode$1);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.IsEmulator {
-  boolean isEmulator();
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.LegacyVrParamsProvider {
-  java.lang.String TAG;
-  android.content.Context context;
-   <init>(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.MutableEglConfigChooser {
-  javax.microedition.khronos.egl.EGLConfig chooseConfig(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig[], boolean);
-  int findConfigAttrib(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int, int);
-   <init>();
-  boolean forceMutableBuffer;
-  boolean IS_EMULATOR;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.NFCUtils {
-  android.content.BroadcastReceiver nfcBroadcastReceiver;
-  void onNFCTagDetected(android.nfc.Tag);
-  boolean isNFCEnabled();
-  android.content.Context context;
-  android.content.IntentFilter createNfcIntentFilter();
-  java.lang.String access$000();
-  java.lang.String TAG;
-  android.content.IntentFilter[] nfcIntentFilters;
-  android.nfc.NfcAdapter nfcAdapter;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.NFCUtils$1 {
-   <init>(com.google.vr.cardboard.NFCUtils);
-  com.google.vr.cardboard.NFCUtils this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.PackageUtils {
-  boolean isSystemPackage(android.content.Context, java.lang.String);
-  boolean isGooglePackage(java.lang.String);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.PpiOverrides {
-  java.util.List PPI_OVERRIDES;
-  java.util.ArrayList supportedDisplaySizes;
-  boolean getPpiOverride(java.util.List, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.google.vr.sdk.proto.nano.Display$DisplayParams);
-  void registerOverridesInternal(java.util.List, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-  java.lang.String TAG;
-  com.google.vr.sdk.proto.nano.Display$DisplayParams getPpiOverride(android.content.Context);
-  java.util.ArrayList getSupportedDisplaySizes(android.view.Display);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.PpiOverrides$PpiOverride {
-  float xPpi;
-  float yPpi;
-  java.lang.String manufacturer;
-  java.lang.String hardware;
-   <init>(java.lang.String, java.lang.String, java.lang.String, java.lang.String, float, float);
-  boolean isMatching(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-  java.lang.String device;
-  java.lang.String model;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.R {
-  boolean sResourcesDidLoad;
-  void onResourcesLoadedString(int);
-  void onResourcesLoadedStyle(int);
-  boolean $assertionsDisabled;
-  void onResourcesLoadedDrawable(int);
-  void onResourcesLoadedColor(int);
-  void onResourcesLoadedId(int);
-  void onResourcesLoadedDimen(int);
-  void onResourcesLoadedLayout(int);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.R$color {
-  int white_transparent;
-  int alignment_marker_color;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.R$dimen {
-  int alignment_marker_height;
-  int alignment_marker_thickness;
-  int transition_bottom_bar_height;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.R$drawable {
-  int quantum_ic_close_white_24;
-  int transition;
-  int rippleable;
-  int quantum_ic_settings_white_24;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.R$id {
-  int transition_icon;
-  int ui_settings_button;
-  int transition_text;
-  int transition_frame;
-  int ui_back_button;
-  int back_button;
-  int ui_alignment_marker;
-  int transition_question_text;
-  int transition_top_frame;
-  int ui_settings_button_holder;
-  int transition_bottom_frame;
-  int ui_back_button_holder;
-  int divider;
-  int transition_switch_action;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.R$layout {
-  int ui_layer_with_portrait_support;
-  int settings_button;
-  int back_button;
-  int ui_layer;
-  int transition_view;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.R$string {
-  int dialog_button_open_help_center;
-  int switch_viewer_prompt;
-  int dialog_title_vr_core_not_enabled;
-  int dialog_title;
-  int dialog_message_no_cardboard;
-  int dialog_title_incompatible_phone;
-  int place_your_phone_into_cardboard;
-  int dialog_vr_core_not_installed;
-  int setup_button;
-  int dialog_title_warning;
-  int settings_button_content_description;
-  int go_to_vr_listeners_settings_button;
-  int dialog_vr_core_not_enabled;
-  int no_browser_text;
-  int dialog_title_vr_core_not_installed;
-  int back_button_content_description;
-  int dialog_message_incompatible_phone;
-  int place_your_viewer_into_viewer_format;
-  int dialog_button_got_it;
-  int go_to_playstore_button;
-  int gvr_vr_mode_component;
-  int switch_viewer_action;
-  int cancel_button;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.R$style {
-  int NoSystemUI;
-  int UiButton;
-  int VrActivityTheme;
-  int GvrDialogTheme;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ScanlineRacingRenderer {
-  com.google.vr.ndk.base.GvrSurfaceView access$000(com.google.vr.cardboard.ScanlineRacingRenderer);
-  void setSurfaceSize(int, int);
-  void setSurfaceView(com.google.vr.ndk.base.GvrSurfaceView);
-   <init>(com.google.vr.ndk.base.GvrApi);
-  void onSurfaceDestroyed();
-  void onPause();
-  com.google.vr.ndk.base.GvrApi gvrApi;
-  com.google.vr.ndk.base.GvrSurfaceView gvrSurfaceView;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ScanlineRacingRenderer$1 {
-   <init>(com.google.vr.cardboard.ScanlineRacingRenderer, int, int);
-  com.google.vr.cardboard.ScanlineRacingRenderer this$0;
-  int val$surfaceWidthPixels;
-  int val$surfaceHeightPixels;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ScreenOrientationDetector {
-  com.google.vr.cardboard.ScreenOrientationDetector$Listener clientListener;
-  int portraitToleranceDegrees;
-  int currentScreenOrientation;
-  int landscapeToleranceDegrees;
-  int determineScreenOrientation(int);
-   <init>(android.content.Context, com.google.vr.cardboard.ScreenOrientationDetector$Listener, int, int);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ScreenOrientationDetector$Listener {
-  void onScreenOrientationChanged(int);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.StoragePermissionUtils {
-  java.lang.String TAG;
-   <init>();
-  void requestStoragePermission(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.SurfaceCreateRecord {
-  java.lang.Runnable surfaceListener;
-  int width;
-  java.lang.Runnable frameListener;
-  int height;
-  android.os.Handler handler;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.ThreadUtils {
-  boolean runningOnUiThread();
-  void runOnUiThread(java.lang.Runnable);
-  android.os.Handler uiHandler;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.TransitionView {
-  int getWidth();
-   <init>(android.content.Context);
-  int getVisibility();
-  boolean isLandscapeRight(int);
-  void setViewerName(java.lang.String);
-  void rotateViewIfNeeded();
-  java.lang.Runnable access$600(com.google.vr.cardboard.TransitionView);
-  int orientation;
-  int access$102(com.google.vr.cardboard.TransitionView, int);
-  android.content.res.Resources getResources();
-  void stopOrientationMonitor();
-  boolean isPortrait(int);
-  void startOrientationMonitor();
-  android.view.OrientationEventListener orientationEventListener;
-  java.lang.Runnable transitionListener;
-  void updateBackButtonVisibility();
-  android.widget.ImageButton backButton;
-  android.view.ViewParent getParent();
-  android.content.Context getContext();
-  int getHeight();
-  void access$300(com.google.vr.cardboard.TransitionView);
-  void fadeOutAndRemove(boolean);
-  void setTransitionListener(java.lang.Runnable);
-  void setBackButtonListener(java.lang.Runnable);
-  void setBackground(android.graphics.drawable.Drawable);
-  android.view.animation.Animation getAnimation();
-  void setVisibility(int);
-  boolean rotationChecked;
-  void access$000(com.google.vr.cardboard.TransitionView, boolean);
-  void setLayoutParams(android.view.ViewGroup$LayoutParams);
-  android.view.View findViewById(int);
-  void removeAllViews();
-  void inflateContentView(int);
-  void clearAnimation();
-  boolean access$400(int);
-  void setOnTouchListener(android.view.View$OnTouchListener);
-  boolean access$500(int);
-  void startAnimation(android.view.animation.Animation);
-  boolean access$200(com.google.vr.cardboard.TransitionView);
-  boolean isLandscapeLeft(int);
-  int getLayoutDirection();
-  java.lang.Runnable backButtonListener;
-  java.lang.Runnable access$700(com.google.vr.cardboard.TransitionView);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.TransitionView$1 {
-  com.google.vr.cardboard.TransitionView this$0;
-   <init>(com.google.vr.cardboard.TransitionView);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.TransitionView$2 {
-   <init>(com.google.vr.cardboard.TransitionView);
-  com.google.vr.cardboard.TransitionView this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.TransitionView$3 {
-  com.google.vr.cardboard.TransitionView this$0;
-   <init>(com.google.vr.cardboard.TransitionView, android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.TransitionView$4 {
-   <init>(com.google.vr.cardboard.TransitionView);
-  com.google.vr.cardboard.TransitionView this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.TransitionView$5 {
-  com.google.vr.cardboard.TransitionView this$0;
-   <init>(com.google.vr.cardboard.TransitionView);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer {
-  java.lang.String viewerName;
-  android.view.View access$700(com.google.vr.cardboard.UiLayer);
-  boolean isAlignmentMarkerEnabled;
-  android.view.View backButtonHolder;
-  void setBackButtonListener(java.lang.Runnable);
-  boolean isSettingsButtonEnabled;
-  int access$1300(com.google.vr.cardboard.UiLayer);
-  android.widget.RelativeLayout rootInnerLayout;
-  boolean transitionViewEnabled;
-  boolean getAlignmentMarkerEnabled();
-  android.content.Context access$000(com.google.vr.cardboard.UiLayer);
-  java.lang.Runnable buttonClickCallbackOverride;
-  android.widget.RelativeLayout alignmentMarker;
-   <init>(android.content.Context);
-  int computeVisibility(boolean);
-  boolean getBackButtonEnabled();
-  android.widget.RelativeLayout access$1100(com.google.vr.cardboard.UiLayer);
-  com.google.vr.cardboard.TransitionView access$1200(com.google.vr.cardboard.UiLayer);
-  android.view.View access$900(com.google.vr.cardboard.UiLayer);
-  void scaleAlignmentMarkerLayoutParams(android.content.Context, float, android.widget.RelativeLayout$LayoutParams);
-  void setViewerName(java.lang.String);
-  void setSettingsButtonEnabled(boolean);
-  boolean isEnabled;
-  java.lang.Runnable backButtonListener;
-  boolean isEnabled();
-  void setTransitionViewListener(java.lang.Runnable);
-  void setEnabled(boolean);
-  java.lang.Runnable access$300(com.google.vr.cardboard.UiLayer);
-  java.lang.Runnable access$100(com.google.vr.cardboard.UiLayer);
-  android.widget.ImageButton settingsButton;
-  float alignmentMarkerScale;
-  void setTransitionViewEnabled(boolean);
-  java.lang.Runnable settingsButtonListener;
-  void setSettingsButtonListener(java.lang.Runnable);
-  android.view.ViewGroup getView();
-  android.content.Context context;
-  com.google.vr.cardboard.TransitionView getTransitionView();
-  com.google.vr.cardboard.TransitionView transitionView;
-  android.widget.ImageButton backButton;
-  com.google.vr.cardboard.TransitionView access$1000(com.google.vr.cardboard.UiLayer);
-  boolean isTransitionViewVisible();
-  android.view.View settingsButtonHolder;
-  java.lang.Runnable transitionListener;
-  android.widget.FrameLayout rootOuterLayout;
-  int currentLayoutId;
-  void access$1400(com.google.vr.cardboard.UiLayer, int);
-  android.widget.ImageButton access$800(com.google.vr.cardboard.UiLayer);
-  android.widget.ImageButton access$600(com.google.vr.cardboard.UiLayer);
-  void inflateViewsWithLayoutId(int);
-  android.widget.FrameLayout access$500(com.google.vr.cardboard.UiLayer);
-  void setButtonClickCallbackOverride(java.lang.Runnable);
-  int access$400(boolean);
-  void setAlignmentMarkerScale(float);
-  java.lang.Runnable access$200(com.google.vr.cardboard.UiLayer);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$1 {
-   <init>(com.google.vr.cardboard.UiLayer);
-  com.google.vr.cardboard.UiLayer this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$10 {
-  com.google.vr.cardboard.UiLayer this$0;
-   <init>(com.google.vr.cardboard.UiLayer, float);
-  float val$scale;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$11 {
-   <init>(com.google.vr.cardboard.UiLayer, boolean);
-  com.google.vr.cardboard.UiLayer this$0;
-  boolean val$enabled;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$12 {
-  com.google.vr.cardboard.UiLayer this$0;
-   <init>(com.google.vr.cardboard.UiLayer, java.lang.Runnable);
-  java.lang.Runnable val$listener;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$13 {
-  com.google.vr.cardboard.UiLayer this$0;
-   <init>(com.google.vr.cardboard.UiLayer, java.lang.String);
-  java.lang.String val$viewerName;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$2 {
-   <init>(com.google.vr.cardboard.UiLayer);
-  com.google.vr.cardboard.UiLayer this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$3 {
-   <init>(com.google.vr.cardboard.UiLayer);
-  com.google.vr.cardboard.UiLayer this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$4 {
-  com.google.vr.cardboard.UiLayer this$0;
-   <init>(com.google.vr.cardboard.UiLayer);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$5 {
-   <init>(com.google.vr.cardboard.UiLayer);
-  com.google.vr.cardboard.UiLayer this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$6 {
-   <init>(com.google.vr.cardboard.UiLayer, boolean);
-  boolean val$enabled;
-  com.google.vr.cardboard.UiLayer this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$7 {
-  boolean val$enabled;
-   <init>(com.google.vr.cardboard.UiLayer, boolean);
-  com.google.vr.cardboard.UiLayer this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$8 {
-  java.lang.Runnable val$listener;
-   <init>(com.google.vr.cardboard.UiLayer, java.lang.Runnable);
-  com.google.vr.cardboard.UiLayer this$0;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$9 {
-  boolean val$enabled;
-  com.google.vr.cardboard.UiLayer this$0;
-   <init>(com.google.vr.cardboard.UiLayer, boolean);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiLayer$RootOuterLayout {
-   <init>(com.google.vr.cardboard.UiLayer, android.content.Context);
-  com.google.vr.cardboard.UiLayer this$0;
-  void handlePotentialConfigurationChange(android.content.res.Configuration);
-  android.content.res.Configuration currentConfig;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiUtils {
-  android.app.AlertDialog$Builder dialogBuilderForTesting;
-  android.app.AlertDialog$Builder createAlertDialogBuilder(android.content.Context);
-  com.google.vr.cardboard.StoragePermissionUtils permissionUtils;
-  void showInstallDialog(android.content.Context);
-  android.app.AlertDialog showDaydreamHelpCenterDialog(android.content.Context, int, int, java.lang.Runnable);
-  android.app.AlertDialog showImmersiveDialog(android.content.Context, android.app.AlertDialog);
-  void launchOrInstallCardboard(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiUtils$1 {
-  android.content.Context val$context;
-   <init>(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiUtils$2 {
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiUtils$3 {
-   <init>(java.lang.Runnable);
-  java.lang.Runnable val$onCancelledCallback;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.UiUtils$4 {
-  android.content.Context val$context;
-   <init>(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.VrContextWrapper {
-  boolean autoFadeEnabled();
-  android.content.ComponentName getVrComponent();
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.VrCoreLibraryLoader {
-  void checkVrCoreGvrLibraryAvailable(android.content.Context, com.google.vr.ndk.base.Version);
-  long loadNativeGvrLibrary(android.content.Context, com.google.vr.ndk.base.Version, com.google.vr.ndk.base.Version);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.VrParamsProvider {
-  com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams readDeviceParams();
-  void close();
-  boolean writeDeviceParams(com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams);
-  com.google.vr.sdk.proto.nano.Display$DisplayParams readDisplayParams();
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams readSdkConfigurationParams(com.google.vr.sdk.proto.nano.SdkConfiguration$SdkConfigurationRequest);
-  com.google.vr.sdk.proto.nano.Preferences$UserPrefs readUserPrefs();
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.VrParamsProviderFactory {
-  com.google.vr.cardboard.VrParamsProviderFactory$ContentProviderClientHandle tryToGetContentProviderClientHandle(android.content.Context);
-  boolean isContentProviderAvailable(android.content.Context);
-  com.google.vr.cardboard.VrParamsProvider create(android.content.Context);
-  com.google.vr.cardboard.VrParamsProvider providerForTesting;
-  java.util.List getValidContentProviderAuthorities(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.VrParamsProviderFactory$ContentProviderClientHandle {
-   <init>(android.content.ContentProviderClient, java.lang.String);
-  java.lang.String authority;
-  android.content.ContentProviderClient client;
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.VrParamsProviderJni {
-  void updateNativePhoneParamsPointer(long, android.util.DisplayMetrics, float);
-  android.util.DisplayMetrics displayMetricsOverride;
-  void nativeUpdateNativePhoneParamsPointer(long, int, int, float, float, float);
-  android.util.DisplayMetrics getDisplayMetrics(android.content.Context, com.google.vr.sdk.proto.nano.Display$DisplayParams);
-}
-
--keep,allowobfuscation class com.google.vr.cardboard.VrSettingsProviderContract {
-  android.net.Uri createUri(java.lang.String, java.lang.String);
-}
-
--keep,allowobfuscation class com.google.vr.internal.controller.ControllerServiceBridge {
-  void access$100(com.google.vr.vrcore.controller.api.ControllerEventPacket2);
-  int vrcoreApiVersion;
-  java.lang.String createListenerKey();
-  void ensureOnMainThread();
-  void access$000(com.google.vr.internal.controller.ControllerServiceBridge, int);
-  void vibrateControllerInternal(int, com.google.vr.vrcore.controller.api.ControllerRequest);
-  void clearControllers();
-  boolean registerListener(int, com.google.vr.internal.controller.ControllerServiceBridge$LocalControllerListener);
-  boolean createAndConnectControllerInternal(int, com.google.vr.internal.controller.ControllerServiceBridge$Callbacks, com.google.vr.vrcore.controller.api.ControllerListenerOptions);
-  void requestBind();
-  void lambda$vibrateController$0$ControllerServiceBridge(int, com.google.vr.vrcore.controller.api.ControllerRequest);
-  void initializeDefaultListener(com.google.vr.internal.controller.ControllerServiceBridge$Callbacks, com.google.vr.vrcore.controller.api.ControllerListenerOptions);
-  com.google.vr.internal.controller.ControllerServiceBridge$LocalControllerListener defaultListener;
-  void doBind();
-  java.lang.String listenerKey;
-  com.google.vr.vrcore.controller.api.IControllerService service;
-  android.content.Context context;
-  void handleAvailableControllersChanged();
-  java.util.concurrent.atomic.AtomicInteger UNIQUE_INT;
-  void setupAndBindDefaultControllerListener();
-   <init>(android.content.Context, com.google.vr.internal.controller.ControllerServiceBridge$Callbacks, int);
-  android.os.Handler mainThreadHandler;
-  android.util.SparseArray controllerListenerMap;
-  void requestUnbind();
-  com.google.vr.internal.controller.ControllerServiceBridge$ControllerServiceListener defaultServiceListener;
-  void logIfControllerPacketLags(com.google.vr.vrcore.controller.api.ControllerEventPacket2);
-  void unregisterListeners();
-   <init>(android.content.Context, com.google.vr.internal.controller.ControllerServiceBridge$Callbacks, com.google.vr.vrcore.controller.api.ControllerListenerOptions);
-  int getNumOfControllers();
-  boolean isBound;
-  int getVrCoreApiVersion(android.content.Context);
-  void handleServiceEvent(int);
-  void bridge$lambda$0$ControllerServiceBridge();
-  void doUnbind();
-}
-
--keep,allowobfuscation class com.google.vr.internal.controller.ControllerServiceBridge$$Lambda$0 {
-  com.google.vr.internal.controller.ControllerServiceBridge arg$1;
-   <init>(com.google.vr.internal.controller.ControllerServiceBridge);
-}
-
--keep,allowobfuscation class com.google.vr.internal.controller.ControllerServiceBridge$$Lambda$1 {
-   <init>(com.google.vr.internal.controller.ControllerServiceBridge);
-  com.google.vr.internal.controller.ControllerServiceBridge arg$1;
-}
-
--keep,allowobfuscation class com.google.vr.internal.controller.ControllerServiceBridge$$Lambda$2 {
-  com.google.vr.internal.controller.ControllerServiceBridge arg$1;
-  com.google.vr.vrcore.controller.api.ControllerRequest arg$3;
-   <init>(com.google.vr.internal.controller.ControllerServiceBridge, int, com.google.vr.vrcore.controller.api.ControllerRequest);
-  int arg$2;
-}
-
--keep,allowobfuscation class com.google.vr.internal.controller.ControllerServiceBridge$$Lambda$3 {
-  com.google.vr.internal.controller.ControllerServiceBridge arg$1;
-   <init>(com.google.vr.internal.controller.ControllerServiceBridge);
-}
-
--keep,allowobfuscation class com.google.vr.internal.controller.ControllerServiceBridge$Callbacks {
-  void onServiceFailed();
-  void onServiceConnected(int);
-  void onServiceDisconnected();
-  void onControllerEventPacket2(com.google.vr.vrcore.controller.api.ControllerEventPacket2);
-  void onControllerEventPacket(com.google.vr.vrcore.controller.api.ControllerEventPacket);
-  void onServiceInitFailed(int);
-  void onServiceUnavailable();
-  void onControllerRecentered(com.google.vr.vrcore.controller.api.ControllerOrientationEvent);
-  void onControllerStateChanged(int, int);
-}
-
--keep,allowobfuscation class com.google.vr.internal.controller.ControllerServiceBridge$ControllerListener {
-  java.lang.ref.WeakReference listener;
-   <init>(com.google.vr.internal.controller.ControllerServiceBridge$LocalControllerListener);
-}
-
--keep,allowobfuscation class com.google.vr.internal.controller.ControllerServiceBridge$ControllerServiceListener {
-   <init>(com.google.vr.internal.controller.ControllerServiceBridge);
-  java.lang.ref.WeakReference serviceBridge;
-}
-
--keep,allowobfuscation class com.google.vr.internal.controller.ControllerServiceBridge$LocalControllerListener {
-  int controllerIndex;
-  com.google.vr.vrcore.controller.api.ControllerListenerOptions options;
-  com.google.vr.internal.controller.ControllerServiceBridge$Callbacks callbacks;
-   <init>(com.google.vr.internal.controller.ControllerServiceBridge$Callbacks, com.google.vr.vrcore.controller.api.ControllerListenerOptions, int);
-}
-
--keep,allowobfuscation class com.google.vr.internal.controller.NativeCallbacks {
-  void handleButtonEvent(long, int, long, int, boolean);
-  void handleEventsCompatibilityLocked(com.google.vr.vrcore.controller.api.ControllerEventPacket);
-  void handleAccelEvent(long, int, long, float, float, float);
-  void handleGyroEvent(long, int, long, float, float, float);
-  void handleServiceUnavailable(long);
-  void handleTouchEvent(long, int, long, int, float, float);
-  boolean closed;
-  void handleOrientationEvent(long, int, long, float, float, float, float);
-  void handleBatteryEvent(long, int, long, boolean, int);
-  void handleServiceInitFailed(long, int);
-  void handleServiceDisconnected(long);
-  void handleServiceConnected(long, int);
-  long userData;
-  void handleStateChanged(long, int, int);
-  void handleServiceFailed(long);
-  void handlePositionEvent(long, int, long, float, float, float);
-  void handleControllerRecentered(long, int, long, float, float, float, float);
-}
-
--keep,allowobfuscation class com.google.vr.keyboard.IGvrKeyboardLoader {
-  void closeGvrKeyboard(long);
-  long loadGvrKeyboard(long);
-}
-
--keep,allowobfuscation class com.google.vr.keyboard.IGvrKeyboardLoader$Stub {
-  long loadGvrKeyboard(long);
-  void attachInterface(android.os.IInterface, java.lang.String);
-  void closeGvrKeyboard(long);
-  com.google.vr.keyboard.IGvrKeyboardLoader asInterface(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.keyboard.IGvrKeyboardLoader$Stub$Proxy {
-  android.os.IBinder mRemote;
-   <init>(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.AbstractDaydreamTouchListener {
-  float[] translation;
-   <init>();
-  float[] lastTranslation;
-  boolean viewerNeedsTouchProcessing();
-  boolean processMotionEvent(android.view.MotionEvent, float, float);
-  float[][] markersInPixels;
-  int mostTouchesSeen;
-  void setLensOffset(float, float, float);
-  boolean isDaydreamImageAlignmentEnabled();
-  float rotation;
-  float xMetersPerPixel;
-  int[] markerBestTouch;
-  void logEvent(int, com.google.common.logging.nano.Vr$VREvent);
-  java.lang.String logTag;
-  boolean useRotationalAlignmentCorrection;
-  void logPhoneAlignment(android.view.MotionEvent, float, float);
-  double[] currentMarkerBestDists;
-  float[] pixelTranslation;
-  void getTranslationInScreenSpace(float[]);
-  float yMetersPerPixel;
-  int[] touchBestMarker;
-  boolean lastMotionEventInHeadset;
-  android.util.DisplayMetrics displayMetrics;
-  int angleSamplesReceived;
-  float borderSizeMeters;
-  void resetTrackingState();
-  float getRotationRadians(android.view.MotionEvent);
-  boolean enabled;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.AndroidCompat {
-  void setSustainedPerformanceMode(android.app.Activity, boolean);
-  boolean setVrModeEnabled(android.app.Activity, boolean);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.BufferSpec {
-  void shutdown();
-  boolean isValidDepthStencilFormat(int);
-   <init>(long);
-  boolean isValidColorFormat(int);
-  long nativeBufferSpec;
-  java.lang.String TAG;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.BufferViewport {
-  void shutdown();
-  java.lang.String TAG;
-   <init>(long);
-  long nativeBufferViewport;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.BufferViewportList {
-  void shutdown();
-   <init>(long);
-  long nativeBufferViewportList;
-  java.lang.String TAG;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.CardboardEmulator {
-  com.google.vr.internal.controller.ControllerServiceBridge controllerServiceBridge;
-  boolean resumed;
-  void onPause();
-  void onResume();
-   <init>(android.content.Context, java.lang.Runnable);
-  com.google.vr.internal.controller.ControllerServiceBridge createServiceBridge(android.content.Context, com.google.vr.internal.controller.ControllerServiceBridge$Callbacks);
-  java.lang.String TAG;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.CardboardEmulator$ControllerCallbacks {
-  java.lang.Runnable cardboardTriggerCallback;
-  void onControllerEventPacket(com.google.vr.vrcore.controller.api.ControllerEventPacket);
-   <init>(java.lang.Runnable);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi {
-  com.google.vr.ndk.base.DaydreamApi create(android.content.Context);
-  android.content.Intent createVrIntent(android.content.ComponentName);
-  void launchInVr(android.app.PendingIntent, android.content.ComponentName);
-  android.content.ServiceConnection connection;
-  void launchInVr(android.app.PendingIntent);
-  java.lang.String access$200();
-  int vrCoreApiVersion;
-  com.google.vr.vrcore.common.api.IVrCoreSdkService access$002(com.google.vr.ndk.base.DaydreamApi, com.google.vr.vrcore.common.api.IVrCoreSdkService);
-  void launchVrHomescreen();
-  boolean isDaydreamReadyPlatform(android.content.Context);
-  android.content.Intent setupVrIntent(android.content.Intent);
-  void launchInVr(android.content.Intent);
-  void close();
-  android.content.ServiceConnection access$500(com.google.vr.ndk.base.DaydreamApi);
-  android.content.Context access$600(com.google.vr.ndk.base.DaydreamApi);
-  int access$400(com.google.vr.ndk.base.DaydreamApi);
-  void runWhenServiceConnected(java.lang.Runnable);
-  boolean supports2dInVr(android.content.Context);
-  com.google.vr.vrcore.common.api.IVrCoreSdkService vrCoreSdkService;
-  java.util.ArrayList queuedRunnables;
-  void checkIntent(android.content.Intent);
-  android.content.Context context;
-  boolean getBooleanSetting(android.content.Context, java.lang.String, boolean);
-  com.google.vr.vrcore.common.api.IDaydreamManager daydreamManager;
-  com.google.vr.vrcore.common.api.IDaydreamManager access$100(com.google.vr.ndk.base.DaydreamApi);
-  void registerDaydreamIntent(android.app.PendingIntent);
-  void unregisterDaydreamIntent();
-  java.lang.String TAG;
-  void checkNotClosed();
-  com.google.vr.vrcore.common.api.IDaydreamManager access$102(com.google.vr.ndk.base.DaydreamApi, com.google.vr.vrcore.common.api.IDaydreamManager);
-  boolean closed;
-  int getCurrentViewerType();
-  void launchTransitionCallbackInVr(com.google.vr.vrcore.common.api.ITransitionCallbacks);
-  com.google.vr.vrcore.common.api.IVrCoreSdkService access$000(com.google.vr.ndk.base.DaydreamApi);
-  boolean isInVrSession(android.content.Context);
-  boolean init();
-  java.util.ArrayList access$300(com.google.vr.ndk.base.DaydreamApi);
-  void exitFromVr(android.app.Activity, int, android.content.Intent);
-   <init>(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$1 {
-   <init>(com.google.vr.ndk.base.DaydreamApi);
-  com.google.vr.ndk.base.DaydreamApi this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$10 {
-   <init>(com.google.vr.ndk.base.DaydreamApi, byte[]);
-  com.google.vr.ndk.base.DaydreamApi this$0;
-  byte[] val$deviceParams;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$11 {
-  com.google.vr.ndk.base.DaydreamApi this$0;
-   <init>(com.google.vr.ndk.base.DaydreamApi);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$12 {
-   <init>(com.google.vr.ndk.base.DaydreamApi);
-  com.google.vr.ndk.base.DaydreamApi this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$2 {
-  com.google.vr.ndk.base.DaydreamApi this$0;
-  android.app.PendingIntent val$intent;
-   <init>(com.google.vr.ndk.base.DaydreamApi, android.app.PendingIntent);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$3 {
-   <init>(com.google.vr.ndk.base.DaydreamApi, android.app.PendingIntent, android.content.ComponentName);
-  com.google.vr.ndk.base.DaydreamApi this$0;
-  android.content.ComponentName val$component;
-  android.app.PendingIntent val$pendingIntent;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$4 {
-  com.google.vr.vrcore.common.api.ITransitionCallbacks val$callbacks;
-   <init>(com.google.vr.ndk.base.DaydreamApi, com.google.vr.vrcore.common.api.ITransitionCallbacks);
-  com.google.vr.ndk.base.DaydreamApi this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$5 {
-   <init>(com.google.vr.ndk.base.DaydreamApi);
-  com.google.vr.ndk.base.DaydreamApi this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$6 {
-  android.app.Activity val$activity;
-  android.app.PendingIntent val$pendingIntent;
-   <init>(com.google.vr.ndk.base.DaydreamApi, android.app.Activity, android.app.PendingIntent, int);
-  int val$requestCode;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$6$1 {
-   <init>(com.google.vr.ndk.base.DaydreamApi$6);
-  com.google.vr.ndk.base.DaydreamApi$6 this$1;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$7 {
-  android.app.PendingIntent val$pendingVrExitIntent;
-   <init>(com.google.vr.ndk.base.DaydreamApi, android.app.PendingIntent);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$8 {
-  java.lang.Runnable val$onFailureRunnable;
-  com.google.vr.ndk.base.DaydreamApi this$0;
-  android.app.PendingIntent val$pendingVrExitIntent;
-   <init>(com.google.vr.ndk.base.DaydreamApi, java.lang.Runnable, android.app.PendingIntent);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamApi$9 {
-  com.google.vr.ndk.base.DaydreamApi this$0;
-   <init>(com.google.vr.ndk.base.DaydreamApi, boolean, android.content.ComponentName);
-  android.content.ComponentName val$componentName;
-  boolean val$shouldInhibit;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamCompatibility {
-   <init>();
-  int getSupportedHeadsets();
-  boolean requiresDaydream();
-   <init>(int);
-  boolean supportsDaydream();
-  boolean supportsCardboard();
-  int supportedHeadsets;
-  int toDeprecated();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamUtils {
-  com.google.vr.ndk.base.DaydreamCompatibility getComponentDaydreamCompatibility(android.content.Context, android.content.ComponentName);
-  boolean checkHeadsetCompatibility(android.content.pm.PackageManager, android.content.ComponentName, java.lang.String);
-  java.lang.String getDeviceParamsDisplayedName(java.lang.String, java.lang.String);
-  boolean sDaydreamPhoneOverrideForTesting;
-  boolean isDaydreamPhone(android.content.Context);
-  boolean canResolveIntent(android.content.pm.PackageManager, android.content.ComponentName, android.content.Intent);
-  com.google.vr.ndk.base.DaydreamCompatibility getComponentDaydreamCompatibility(android.content.pm.PackageManager, android.content.ComponentName);
-  boolean isDaydreamViewer(com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DaydreamUtilsWrapper {
-  boolean isDaydreamActivity(android.app.Activity);
-  boolean isDaydreamComponent(android.content.Context);
-  boolean isDaydreamPhone(android.content.Context);
-  boolean isDaydreamRequiredComponent(android.content.Context);
-  com.google.vr.ndk.base.DaydreamCompatibility getComponentDaydreamCompatibility(android.content.Context);
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.DefaultNativeLibraryLoader {
-  boolean shouldIgnoreDefaultLibrary;
-  void maybeLoadDefaultLibrary();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.Event {
-  void close();
-  long nativeEvent;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ExtensionManager {
-  void shutdown();
-  void onResume();
-  void onPause();
-  void reportTelemetry(com.google.vr.vrcore.logging.api.IVrCoreLoggingService);
-  boolean bootsToVr();
-  void setEnabled(boolean);
-  void initialize(android.view.ViewGroup, com.google.vr.ndk.base.GvrApi);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ExternalSurface {
-   <init>(com.google.vr.ndk.base.GvrApi, com.google.vr.ndk.base.GvrLayout$ExternalSurfaceListener, android.os.Handler);
-  void shutdown();
-  java.lang.String TAG;
-  long nativeExternalSurface;
-  int getId();
-  android.view.Surface getSurface();
-  java.lang.String access$000();
-  long getNativeExternalSurface();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ExternalSurface$1 {
-  com.google.vr.ndk.base.GvrLayout$ExternalSurfaceListener val$listener;
-  com.google.vr.ndk.base.ExternalSurface this$0;
-   <init>(com.google.vr.ndk.base.ExternalSurface, com.google.vr.ndk.base.GvrLayout$ExternalSurfaceListener);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ExternalSurface$2 {
-   <init>(com.google.vr.ndk.base.ExternalSurface, com.google.vr.ndk.base.GvrLayout$ExternalSurfaceListener);
-  com.google.vr.ndk.base.GvrLayout$ExternalSurfaceListener val$listener;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.FadeOverlayView {
-  void access$000(com.google.vr.ndk.base.FadeOverlayView);
-   <init>(android.content.Context, boolean);
-  java.lang.Runnable fadeUpdateRunnable;
-  void setEnabled(boolean);
-  boolean flushAutoFadeOnVisible;
-  void postOnAnimation(java.lang.Runnable);
-  int getVisibility();
-  boolean removeCallbacks(java.lang.Runnable);
-  int fadeType;
-  boolean post(java.lang.Runnable);
-  void flushAutoFade();
-  void setBackgroundColor(int);
-  void setAlpha(float);
-  long fadeDurationMillis;
-  long fadeStartTimeMillis;
-  void updateFade();
-  boolean isEnabled();
-  void startFade(int, long, int);
-  boolean autoFadeEnabled;
-  void onInvisible();
-  boolean visible;
-  void endFade();
-  android.os.Handler autoFadeHandler;
-  float fadeStartOpacity;
-  void onVisible();
-  float getAlpha();
-  void setVisibility(int);
-  void removeFadeCallbacks();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.FadeOverlayView$1 {
-   <init>(com.google.vr.ndk.base.FadeOverlayView);
-  com.google.vr.ndk.base.FadeOverlayView this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.FadeOverlayView$2 {
-   <init>(com.google.vr.ndk.base.FadeOverlayView, android.os.Looper);
-  com.google.vr.ndk.base.FadeOverlayView this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.Frame {
-   <init>();
-  long getNativeFrame();
-  void checkAccess();
-  java.lang.String TAG;
-  long nativeFrame;
-  void setNativeFrame(long);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrApi {
-  int[] nativeGetWindowBounds(long);
-  long nativeGvrContext;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams getSdkConfigurationParams();
-  int nativeGetViewerType(long);
-  int nativeExternalSurfaceGetId(long);
-  void nativeSetApplicationState(java.lang.ClassLoader, android.content.Context);
-  boolean IS_ROBOLECTRIC_BUILD;
-  boolean getAsyncReprojectionEnabled();
-  float nativeGetBorderSizeMeters(long);
-  void nativeGetHeadSpaceFromStartSpaceTransform(long, float[], long);
-  void nativeGetHeadSpaceFromStartSpaceRotation(long, float[], long);
-  void nativeBufferViewportGetSourceUv(long, android.graphics.RectF);
-  java.util.ArrayList swapChainRefs;
-  void nativeBufferViewportSetReprojection(long, int);
-  void nativeResetTracking(long);
-  void nativeReleaseGvrContext(long);
-  void nativeGetScreenTargetSize(long, android.graphics.Point);
-  boolean nativeSetAsyncReprojectionEnabled(long, boolean);
-  void nativeSwapChainGetBufferSize(long, int, android.graphics.Point);
-  int nativeUserPrefsGetControllerHandedness(long);
-  void nativeBufferViewportGetTransform(long, float[]);
-  android.content.Context context;
-  long nativeBufferViewportCreate(long);
-  com.google.vr.ndk.base.ExternalSurface createExternalSurface(com.google.vr.ndk.base.GvrLayout$ExternalSurfaceListener, android.os.Handler);
-  boolean nativeIsFeatureSupported(long, int);
-  void resumeTrackingSetState(byte[]);
-  long nativeValueGetFlags(long);
-  boolean nativeSetDefaultViewerProfile(long, java.lang.String);
-  void nativeResume(long);
-  void refreshDisplayMetrics();
-  void onSurfaceCreatedReprojectionThread();
-  void nativeSetDisplayMetrics(long, int, int, float, float);
-  byte[] pauseTrackingGetState();
-  void requestContextSharing(com.google.vr.cardboard.EglReadyListener);
-  long nativeGetEventFlags(long);
-  java.lang.String nativeGetErrorString(int);
-  java.lang.String nativeGetViewerModel(long);
-  boolean usingDynamicLibrary(android.content.Context);
-  void nativePauseTracking(long);
-  android.graphics.Point renderReprojectionThread();
-  com.google.vr.cardboard.DisplaySynchronizer displaySynchronizer;
-  void nativeSetSurfaceSize(long, int, int);
-  void recenterTracking();
-  int nativeFrameGetFramebufferObject(long, int);
-  int nativeValueAsInt(long);
-  boolean nativeGetAsyncReprojectionEnabled(long);
-  void dumpDebugData();
-  com.google.vr.cardboard.DisplaySynchronizer createDefaultDisplaySynchronizer(android.content.Context);
-  long nativeValueAsFlags(long);
-  void nativeBufferViewportSetSourceBufferIndex(long, int);
-  void nativeValueAsMat4f(long, float[]);
-  android.view.Surface nativeExternalSurfaceGetSurface(long);
-  void nativeBufferViewportListSetItem(long, int, long);
-  void nativeSetDefaultFramebufferActive(long);
-  int nativeGetEventType(long);
-  void nativeBufferViewportSetTransform(long, float[]);
-  void nativeBufferSpecSetSamples(long, int);
-  int nativeBufferViewportListGetSize(long);
-  void onPauseReprojectionThread();
-  com.google.vr.ndk.base.Properties properties;
-  android.util.DisplayMetrics computeCurrentDisplayMetrics(com.google.vr.sdk.proto.nano.Display$DisplayParams);
-  long nativeBufferSpecCreate(long);
-  void shutdown();
-  void nativeInitializeGl(long);
-  long nativeGetCurrentProperties(long);
-  void nativeBufferViewportGetSourceFov(long, android.graphics.RectF);
-  void nativePause(long);
-  void nativeSwapChainResizeBuffer(long, int, int, int);
-  boolean nativeSetViewerParams(long, byte[]);
-  long nativeCreateEvent();
-  void setSurfaceSize(int, int);
-  void nativeFrameGetBufferSize(long, int, android.graphics.Point);
-  void nativeBufferViewportDestroy(long);
-  void nativeFrameSubmit(long, long, float[]);
-  int nativeBufferSpecGetSamples(long);
-  void setApplicationState(android.content.Context);
-  int nativeBufferViewportGetExternalSurfaceId(long);
-  boolean nativeUsingDynamicLibrary();
-  void nativeFrameUnbind(long);
-  void nativeBufferSpecSetDepthStencilFormat(long, int);
-  void setIdleListener(com.google.vr.ndk.base.GvrApi$IdleListener);
-  void nativeGetRecenterEventStartSpaceFromTrackingSpaceTransform(long, float[]);
-  void nativeSetLensOffset(long, float, float, float);
-  long nativeGetRecenterEventFlags(long);
-  int nativeGetError(long);
-  android.graphics.Point nativeRenderReprojectionThread(long);
-  void nativeSetIdleListener(long, com.google.vr.ndk.base.GvrApi$IdleListener);
-   <init>(android.content.Context, long);
-  com.google.vr.cardboard.VrParamsProvider vrParamsProvider;
-  void nativeBufferViewportSetSourceLayer(long, int);
-  void setLensOffset(float, float, float);
-  void nativeOnPauseReprojectionThread(long);
-   <init>(android.content.Context, com.google.vr.cardboard.DisplaySynchronizer);
-  void nativeBufferViewportSetTargetEye(long, int);
-  void nativeResumeTracking(long);
-  void nativeSetIgnoreManualPauseResumeTracker(long, boolean);
-  int nativeBufferViewportGetSourceBufferIndex(long);
-  void nativeGetEyeFromHeadMatrix(long, int, float[]);
-  boolean isFeatureSupported(int);
-  void nativeDestroyEvent(long);
-  boolean nativeGetProperty(long, int, long);
-  int nativeSwapChainGetBufferCount(long);
-  void resume();
-  long nativeGetUserPrefs(long);
-  long getNativeGvrContext();
-  void nativeBufferSpecSetSize(long, int, int);
-  long nativeSwapChainCreate(long, long[]);
-  void nativeGetMaximumEffectiveRenderTargetSize(long, android.graphics.Point);
-  void nativeBufferViewportSetOpacity(long, float);
-  float nativeBufferViewportGetOpacity(long);
-  void nativeSwapChainDestroy(long);
-  void setDisplayMetrics(android.util.DisplayMetrics);
-  byte[] nativePauseTrackingGetState(long);
-  boolean setAsyncReprojectionEnabled(boolean);
-  void nativeBufferViewportListDestroy(long);
-  void nativeRequestContextSharing(long, com.google.vr.cardboard.EglReadyListener);
-  boolean nativeUsingShimLibrary();
-  void nativeBufferViewportSetSourceUv(long, float, float, float, float);
-  void nativeBufferSpecSetMultiviewLayers(long, int);
-  boolean nativeUsingVrDisplayService(long);
-  void nativeDumpDebugData(long);
-  java.lang.String nativeGetViewerVendor(long);
-  long nativeExternalSurfaceCreateWithListeners(long, java.lang.Runnable, java.lang.Runnable, android.os.Handler);
-  void nativeBufferViewportSetSourceFov(long, float, float, float, float);
-  void nativeFrameBindBuffer(long, int);
-  long nativeCreateValue();
-  void nativeResumeTrackingSetState(long, byte[]);
-  int nativeClearError(long);
-  com.google.vr.ndk.base.GvrApi$PoseTracker sPoseTrackerForTesting;
-  void nativeBufferViewportListGetItem(long, int, long);
-  long nativeCreate(java.lang.ClassLoader, android.content.Context, long, int, int, float, float, com.google.vr.ndk.base.GvrApi$PoseTracker);
-  void nativeRecenterTracking(long);
-  float nativeValueAsFloat(long);
-  boolean nativePollEvent(long, long);
-  com.google.vr.ndk.base.UserPrefs userPrefs;
-  void getEyeFromHeadMatrix(int, float[]);
-  boolean usingShimLibrary();
-  void nativeOnSurfaceChangedReprojectionThread(long);
-  long nativeBufferViewportListCreate(long);
-  void onSurfaceChangedReprojectionThread();
-  void nativeSetDynamicLibraryLoadingEnabled(boolean);
-  void nativeBufferSpecGetSize(long, android.graphics.Point);
-  void setIgnoreManualTrackerPauseResume(boolean);
-  boolean usingVrDisplayService();
-  int nativeBufferViewportGetReprojection(long);
-  void nativeDestroyValue(long);
-  int getViewerType();
-  int nativeGetRecenterEventType(long);
-  void nativeDistortToScreen(long, int, long, float[], long);
-  void nativeBufferViewportSetExternalSurfaceId(long, int);
-  boolean setViewerParams(byte[]);
-  void nativeExternalSurfaceDestroy(long);
-  boolean nativeBufferViewportEqual(long, long);
-  float[] nativeComputeDistortedPoint(long, int, float[]);
-  void nativeBufferSpecSetColorFormat(long, int);
-  long nativeGetEventTimestamp(long);
-  void nativeGetRecommendedBufferViewports(long, long);
-  boolean ownsNativeGvrContext;
-  void pause();
-  void nativeGetScreenBufferViewports(long, long);
-  void nativeBufferSpecDestroy(long);
-  boolean isOpenGLKHRDebugEnabled();
-  void nativeOnSurfaceCreatedReprojectionThread(long);
-  long nativeSwapChainAcquireFrame(long);
-  void nativeReconnectSensors(long);
-  int nativeBufferViewportGetTargetEye(long);
-  void nativeBufferViewportSetExternalSurface(long, long);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayout {
-  com.google.vr.ndk.base.GvrApi getGvrApi();
-  void addView(android.view.View);
-   <init>(android.content.Context);
-  void onPause();
-  boolean dispatchTouchEvent(android.view.MotionEvent);
-  void onSizeChanged(int, int, int, int);
-  void onResume();
-  com.google.vr.vrcore.library.api.IGvrLayout impl;
-  com.google.vr.ndk.base.ExternalSurface videoSurface;
-  void shutdown();
-  void init();
-  com.google.vr.ndk.base.GvrUiLayout uiLayout;
-  com.google.vr.ndk.base.GvrApi gvrApi;
-  boolean onGenericMotionEvent(android.view.MotionEvent);
-  boolean dispatchKeyEvent(android.view.KeyEvent);
-  android.content.Context getContext();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayout$ExternalSurfaceListener {
-  void onSurfaceAvailable(android.view.Surface);
-  void onFrameAvailable();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutFactory {
-  com.google.vr.vrcore.library.api.IGvrLayout create(android.content.Context);
-  com.google.vr.vrcore.library.api.IGvrLayout tryCreateFromVrCorePackage(android.content.Context);
-  com.google.vr.vrcore.library.api.IGvrLayout createFromCurrentPackage(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl {
-  com.google.vr.ndk.base.GvrLayoutImpl$PresentationHelper presentationHelper;
-  com.google.vr.ndk.base.GvrLayoutImpl$PresentationHelper tryCreatePresentationHelper();
-  boolean isPresenting();
-  com.google.vr.ndk.base.GvrLayoutImpl$FrameFlushWorkaround frameFlushWorkaround;
-  void onPause();
-  void updateUiLayout();
-  com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager screenOnManager;
-  com.google.vr.ndk.base.GvrUiLayoutImpl uiLayout;
-  boolean isContextSharingEnabled();
-  boolean isResumed;
-  com.google.vr.cardboard.ScanlineRacingRenderer access$200(com.google.vr.ndk.base.GvrLayoutImpl);
-  android.view.View presentationView;
-  void addView(android.view.View, int);
-   <init>(android.content.Context, com.google.vr.ndk.base.ExtensionManager);
-  int asyncReprojectionFlags;
-  com.google.vr.ndk.base.VrCoreSdkClient getVrCoreSdkClient();
-  com.google.vr.cardboard.EglReadyListener eglReadyListener;
-   <init>(android.content.Context);
-  com.google.vr.ndk.base.VrCoreSdkClient access$100(com.google.vr.ndk.base.GvrLayoutImpl);
-  com.google.vr.cardboard.EglFactory eglFactory;
-  boolean attachedToWindow;
-  com.google.vr.ndk.base.FadeOverlayView fadeOverlayView;
-  com.google.vr.ndk.base.GvrUiLayoutImpl access$300(com.google.vr.ndk.base.GvrLayoutImpl);
-  boolean removeCallbacks(java.lang.Runnable);
-  com.google.vr.ndk.base.GvrLayoutImpl$AsyncReprojectionSurfaceView scanlineRacingView;
-  com.google.vr.ndk.base.VrCoreSdkClient createVrCoreSdkClient(android.content.Context, com.google.vr.ndk.base.GvrApi, com.google.vr.ndk.base.DaydreamUtilsWrapper, com.google.vr.ndk.base.FadeOverlayView);
-  com.google.vr.ndk.base.GvrLayoutImpl$PresentationFactory access$500();
-  com.google.vr.ndk.base.ExtensionManager extensionManager;
-  com.google.vr.ndk.base.ExternalSurface videoSurface;
-  boolean enableCardboardTriggerEmulation(java.lang.Runnable);
-  int getWindowVisibility();
-  boolean autoFadeEnabled;
-  boolean postDelayed(java.lang.Runnable, long);
-  com.google.vr.ndk.base.GvrApi gvrApi;
-  com.google.vr.ndk.base.SdkDaydreamTouchListener daydreamTouchListener;
-  void onResume();
-  android.content.Context getContext();
-  android.widget.FrameLayout presentationLayout;
-  com.google.vr.ndk.base.CardboardEmulator cardboardEmulator;
-  com.google.vr.ndk.base.SdkDaydreamTouchListener createDaydreamTouchListener();
-  void initWithInjectedObjects(com.google.vr.ndk.base.GvrApi, com.google.vr.cardboard.DisplaySynchronizer, com.google.vr.cardboard.EglReadyListener, com.google.vr.ndk.base.FadeOverlayView, com.google.vr.ndk.base.DaydreamUtilsWrapper, com.google.vr.ndk.base.ExtensionManager, com.google.vr.ndk.base.GvrUiLayoutImpl);
-  void addScanlineRacingView();
-  com.google.vr.cardboard.ScanlineRacingRenderer scanlineRacingRenderer;
-  com.google.vr.ndk.base.GvrApi getGvrApi();
-  void removeView(android.view.View);
-  void access$000(com.google.vr.ndk.base.GvrLayoutImpl, int);
-  void setPresentationView(android.view.View);
-  void setStereoModeEnabled(boolean);
-  boolean isDeviceDetectionEnabled();
-  boolean enableAsyncReprojection(int);
-  java.lang.Runnable showRenderingViewsRunnable;
-  void updateFadeVisibility();
-  boolean stereoModeEnabled;
-  com.google.vr.ndk.base.GvrLayoutImpl$PresentationFactory sOptionalPresentationFactory;
-  void init(com.google.vr.ndk.base.ExtensionManager);
-  boolean isDimUiEnabled();
-  void setReentryIntent(android.app.PendingIntent);
-  com.google.vr.ndk.base.GvrUiLayoutImpl getUiLayoutImpl();
-  void onBackPressed();
-  void setStereoModeEnabledImpl(boolean);
-  void shutdown();
-  com.google.vr.cardboard.DisplaySynchronizer displaySynchronizer;
-  boolean setOnDonNotNeededListener(java.lang.Runnable);
-  void lambda$setStereoModeEnabled$0$GvrLayoutImpl(boolean);
-  void updateRenderingViewsVisibility(int);
-  com.google.vr.ndk.base.VrCoreSdkClient vrCoreSdkClient;
-  com.google.vr.ndk.base.DaydreamUtilsWrapper daydreamUtils;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$$Lambda$0 {
-  com.google.vr.ndk.base.GvrLayoutImpl arg$1;
-  boolean arg$2;
-   <init>(com.google.vr.ndk.base.GvrLayoutImpl, boolean);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$1 {
-  com.google.vr.ndk.base.GvrLayoutImpl this$0;
-   <init>(com.google.vr.ndk.base.GvrLayoutImpl);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$2 {
-  com.google.vr.ndk.base.GvrLayoutImpl this$0;
-   <init>(com.google.vr.ndk.base.GvrLayoutImpl);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$3 {
-   <init>(com.google.vr.ndk.base.GvrLayoutImpl);
-  com.google.vr.ndk.base.GvrLayoutImpl this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$4 {
-   <init>(com.google.vr.ndk.base.GvrLayoutImpl);
-  com.google.vr.ndk.base.GvrLayoutImpl this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$AsyncReprojectionSurfaceView {
-  void setEGLWindowSurfaceFactory(android.opengl.GLSurfaceView$EGLWindowSurfaceFactory);
-   <init>(android.content.Context);
-  void setEGLConfigChooser(android.opengl.GLSurfaceView$EGLConfigChooser);
-  void setVisibility(int);
-  void setSwapMode(int);
-  void setRenderer(com.google.vr.cardboard.ScanlineRacingRenderer);
-  boolean isDetachedFromWindow();
-  void onSurfaceDestroyed(java.lang.Runnable);
-  void setEGLContextFactory(android.opengl.GLSurfaceView$EGLContextFactory);
-  void onResume();
-  com.google.vr.cardboard.ScanlineRacingRenderer access$400(com.google.vr.ndk.base.GvrLayoutImpl$AsyncReprojectionSurfaceView);
-  void setEglReadyListener(com.google.vr.cardboard.EglReadyListener);
-  void onPause(java.lang.Runnable);
-  com.google.vr.cardboard.ScanlineRacingRenderer scanlineRacingRenderer;
-  void onPause();
-  void setZOrderMediaOverlay(boolean);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$AsyncReprojectionSurfaceView$1 {
-   <init>(com.google.vr.ndk.base.GvrLayoutImpl$AsyncReprojectionSurfaceView);
-  com.google.vr.ndk.base.GvrLayoutImpl$AsyncReprojectionSurfaceView this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$FrameFlushWorkaround {
-  android.view.Choreographer choreographer;
-  int framesRemaining;
-   <init>();
-  void onResume();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$PresentationFactory {
-  android.app.Presentation create(android.content.Context, android.view.Display);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$PresentationHelper {
-  android.hardware.display.DisplayManager displayManager;
-   <init>(android.content.Context, android.widget.FrameLayout, android.view.View, com.google.vr.cardboard.DisplaySynchronizer, java.lang.String);
-  android.widget.RelativeLayout$LayoutParams layout;
-  android.view.View view;
-  boolean hasCurrentPresentationExpired();
-  void shutdown();
-  void setDisplay(android.view.Display);
-  void addListener(com.google.vr.ndk.base.GvrLayoutImpl$PresentationListener);
-  android.app.Presentation presentation;
-  com.google.vr.cardboard.DisplaySynchronizer displaySynchronizer;
-  void onResume();
-  void onDetachedFromWindow();
-  boolean isPresenting();
-  boolean isValidExternalDisplay(android.view.Display);
-  void detachViewFromParent(android.view.View);
-  void onPause();
-  android.widget.FrameLayout originalParent;
-  android.content.Context context;
-  java.lang.String externalDisplayName;
-  java.util.List listeners;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$PresentationListener {
-  void onPresentationStarted(android.view.Display);
-  void onPresentationStopped();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager {
-  long access$800(com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager);
-  long QUIET_PERIOD_AFTER_RESUME_MILLIS;
-  boolean isIdle;
-  long access$900();
-  android.view.View parentView;
-  boolean access$600(com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager);
-  boolean access$1000(com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager);
-   <init>(android.view.View);
-  void onPause();
-  boolean isResumed;
-  boolean access$602(com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager, boolean);
-  void onResume();
-  void access$700(com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager);
-  boolean access$1002(com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager, boolean);
-  void updateSetScreenOn();
-  long lastResumeTimeMillis;
-  void setEnabled(boolean);
-  boolean isEnabled;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager$1 {
-   <init>(com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager, boolean);
-  boolean val$newIsEnabled;
-  com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager$2 {
-   <init>(com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager, boolean);
-  com.google.vr.ndk.base.GvrLayoutImpl$ScreenOnManager this$0;
-  boolean val$newIsIdle;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrLayoutImplWrapper {
-  com.google.vr.ndk.base.GvrLayoutImpl impl;
-   <init>(com.google.vr.ndk.base.GvrLayoutImpl);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView {
-  int mEGLContextClientVersion;
-  android.opengl.GLSurfaceView$EGLConfigChooser access$500(com.google.vr.ndk.base.GvrSurfaceView);
-  void setEGLConfigChooser(android.opengl.GLSurfaceView$EGLConfigChooser);
-  android.opengl.GLSurfaceView$Renderer access$1000(com.google.vr.ndk.base.GvrSurfaceView);
-  boolean mPreserveEGLContextOnPause;
-  void onPause();
-   <init>(android.content.Context);
-  void init();
-  android.opengl.GLSurfaceView$EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
-  com.google.vr.cardboard.EglReadyListener access$300(com.google.vr.ndk.base.GvrSurfaceView);
-  boolean mDetached;
-  com.google.vr.ndk.base.GvrSurfaceView$GLWrapper mGLWrapper;
-  android.opengl.GLSurfaceView$EGLContextFactory mEGLContextFactory;
-  void onSurfaceDestroyed(java.lang.Runnable);
-  void queueEvent(java.lang.Runnable);
-  void onResume();
-  int access$800(com.google.vr.ndk.base.GvrSurfaceView);
-  android.opengl.GLSurfaceView$EGLWindowSurfaceFactory access$600(com.google.vr.ndk.base.GvrSurfaceView);
-  void setEGLContextClientVersion(int);
-  com.google.vr.ndk.base.GvrSurfaceView$GLThread mGLThread;
-  android.opengl.GLSurfaceView$Renderer mRenderer;
-  int access$200(com.google.vr.ndk.base.GvrSurfaceView);
-  com.google.vr.cardboard.EglReadyListener mAppContextListener;
-  void setRenderer(android.opengl.GLSurfaceView$Renderer);
-   <init>(android.content.Context, android.util.AttributeSet);
-  void onAttachedToWindow();
-  void checkRenderThreadState();
-  android.opengl.GLSurfaceView$EGLConfigChooser mEGLConfigChooser;
-  int mDebugFlags;
-  void requestExitAndWait();
-  boolean access$900(com.google.vr.ndk.base.GvrSurfaceView);
-  boolean mPreserveGlThreadOnDetachedFromWindow;
-  java.lang.ref.WeakReference mThisWeakRef;
-  com.google.vr.ndk.base.GvrSurfaceView$GLWrapper access$700(com.google.vr.ndk.base.GvrSurfaceView);
-  android.opengl.GLSurfaceView$EGLContextFactory access$400(com.google.vr.ndk.base.GvrSurfaceView);
-  void onDetachedFromWindow();
-  android.view.SurfaceHolder getHolder();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$BaseConfigChooser {
-  com.google.vr.ndk.base.GvrSurfaceView this$0;
-  int[] mConfigSpec;
-  javax.microedition.khronos.egl.EGLConfig chooseConfig(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig[]);
-   <init>(com.google.vr.ndk.base.GvrSurfaceView, int[]);
-  javax.microedition.khronos.egl.EGLConfig chooseConfig(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay);
-  int[] filterConfigSpec(int[]);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$ComponentSizeChooser {
-  int mGreenSize;
-  int mAlphaSize;
-  int mBlueSize;
-  int mRedSize;
-  int findConfigAttrib(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int, int);
-  int mDepthSize;
-  int mStencilSize;
-   <init>(com.google.vr.ndk.base.GvrSurfaceView, int, int, int, int, int, int);
-  int[] mValue;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$DefaultContextFactory {
-   <init>(com.google.vr.ndk.base.GvrSurfaceView);
-   <init>(com.google.vr.ndk.base.GvrSurfaceView, com.google.vr.ndk.base.GvrSurfaceView$1);
-  com.google.vr.ndk.base.GvrSurfaceView this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$DefaultWindowSurfaceFactory {
-   <init>();
-   <init>(com.google.vr.ndk.base.GvrSurfaceView$1);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$EglHelper {
-  void initialize();
-  int swap();
-  javax.microedition.khronos.opengles.GL createGL();
-  void start();
-  void finish();
-  java.lang.String getHex(int);
-  java.lang.String getErrorString(int);
-  javax.microedition.khronos.egl.EGLContext mEglContext;
-  javax.microedition.khronos.egl.EGLSurface mEglSurface;
-  void setEglSurfaceAttrib(int, int);
-  void destroySurfaceImp();
-  void logEglErrorAsWarning(java.lang.String, java.lang.String, int);
-  void createPendingEglContext();
-  void destroySurface();
-  void throwEglException(java.lang.String);
-  void throwEglException(java.lang.String, int);
-  javax.microedition.khronos.egl.EGLConfig mEglConfig;
-  javax.microedition.khronos.egl.EGLDisplay mPendingEglDisplay;
-   <init>(java.lang.ref.WeakReference);
-  boolean createSurface();
-  java.lang.ref.WeakReference mGvrSurfaceViewWeakRef;
-  javax.microedition.khronos.egl.EGLContext mPendingEglContext;
-  javax.microedition.khronos.egl.EGL10 mEgl;
-  javax.microedition.khronos.egl.EGLDisplay mEglDisplay;
-  java.lang.String formatEglError(java.lang.String, int);
-  void renewPendingEglContext();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$GLThread {
-  void setName(java.lang.String);
-  void guardedRun();
-  boolean mPaused;
-  void onWindowResize(int, int);
-  boolean ableToDraw();
-  com.google.vr.ndk.base.GvrSurfaceView$GLThread$GLThreadManager mGLThreadManager;
-  boolean mSizeChanged;
-  void setRenderMode(int);
-  void setSwapMode(int);
-  boolean mRenderComplete;
-  boolean mHaveEglSurface;
-  boolean mShouldExit;
-  int mRenderMode;
-  boolean mHasSurface;
-  boolean mSurfaceIsBad;
-  boolean readyToDraw();
-  void onPause(java.lang.Runnable);
-  boolean mWaitingForSurface;
-  void requestRender();
-  void onResume();
-  void start();
-  int getRenderMode();
-  int mHeight;
-  boolean mRequestRender;
-  boolean mFinishedCreatingEglSurface;
-  int getSwapMode();
-  int mWidth;
-  int mRequestedSwapMode;
-  void stopEglSurfaceLocked();
-  boolean mShouldReleaseEglContext;
-  void stopEglContextLocked();
-  java.lang.ref.WeakReference mGvrSurfaceViewWeakRef;
-  boolean access$1102(com.google.vr.ndk.base.GvrSurfaceView$GLThread, boolean);
-  void surfaceDestroyed(java.lang.Runnable);
-  boolean mHaveEglContext;
-  void requestExitAndWait();
-  void surfaceCreated();
-   <init>(java.lang.ref.WeakReference);
-  long getId();
-  java.util.ArrayList mEventQueue;
-  boolean mRequestPaused;
-  void requestRenderAndWait();
-  void queueEvent(java.lang.Runnable);
-  boolean mExited;
-  boolean mWantRenderNotification;
-  com.google.vr.ndk.base.GvrSurfaceView$EglHelper mEglHelper;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$GLThread$GLThreadManager {
-  void releaseEglContextLocked(com.google.vr.ndk.base.GvrSurfaceView$GLThread);
-   <init>(com.google.vr.ndk.base.GvrSurfaceView$1);
-  void threadExiting(com.google.vr.ndk.base.GvrSurfaceView$GLThread);
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$GLWrapper {
-  javax.microedition.khronos.opengles.GL wrap(javax.microedition.khronos.opengles.GL);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$LogWriter {
-  java.lang.StringBuilder mBuilder;
-  void flushBuilder();
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrSurfaceView$SimpleEGLConfigChooser {
-   <init>(com.google.vr.ndk.base.GvrSurfaceView, boolean);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrUiLayout {
-  void setSettingsButtonListener(java.lang.Runnable);
-  com.google.vr.vrcore.library.api.IGvrUiLayout impl;
-   <init>(com.google.vr.vrcore.library.api.IGvrUiLayout);
-  void setCloseButtonListener(java.lang.Runnable);
-  void launchOrInstallGvrApp(android.app.Activity);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrUiLayoutImpl {
-  android.animation.ObjectAnimator uiLayerDimmingAnimation;
-  void cancelDimmingUiLayer();
-  void setDimmedUiTouchOverride();
-  void delayDimmingUiLayer(long);
-  android.view.ViewGroup getRoot();
-  void setEnabled(boolean);
-   <init>(android.content.Context, java.lang.Runnable, com.google.vr.ndk.base.DaydreamUtilsWrapper);
-  void lambda$setDimmedUiTouchOverride$0$GvrUiLayoutImpl();
-  com.google.vr.ndk.base.GvrUiLayoutImpl$CloseButtonListenerWrapper closeButtonListener;
-  com.google.vr.cardboard.UiLayer uiLayer;
-  java.lang.Runnable access$000(android.content.Context, com.google.vr.ndk.base.DaydreamUtilsWrapper);
-  java.lang.Runnable createDefaultCloseButtonListener(android.content.Context, com.google.vr.ndk.base.DaydreamUtilsWrapper);
-  void invokeCloseButtonListener();
-  void beginDimmingUiLayer();
-  void delayDimmingUiLayerAfterVisible();
-  boolean daydreamModeEnabled;
-  void bridge$lambda$0$GvrUiLayoutImpl();
-  java.lang.Runnable beginDimmingUiLayerRunnable;
-  java.lang.Runnable delayDimmingUiLayerAfterVisibleRunnable;
-  void setDaydreamModeEnabled(boolean);
-   <init>(android.content.Context, java.lang.Runnable);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrUiLayoutImpl$$Lambda$0 {
-  com.google.vr.ndk.base.GvrUiLayoutImpl arg$1;
-   <init>(com.google.vr.ndk.base.GvrUiLayoutImpl);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrUiLayoutImpl$$Lambda$1 {
-  com.google.vr.ndk.base.GvrUiLayoutImpl arg$1;
-   <init>(com.google.vr.ndk.base.GvrUiLayoutImpl);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrUiLayoutImpl$$Lambda$2 {
-   <init>(com.google.vr.ndk.base.GvrUiLayoutImpl);
-  com.google.vr.ndk.base.GvrUiLayoutImpl arg$1;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrUiLayoutImpl$1 {
-  android.content.Intent val$homeIntent;
-  android.content.Context val$context;
-   <init>(android.content.Context, android.content.Intent);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrUiLayoutImpl$2 {
-  android.app.Activity val$activity;
-  android.content.Intent val$homeIntent;
-   <init>(android.app.Activity, android.content.Intent);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrUiLayoutImpl$3 {
-   <init>(android.app.Activity);
-  android.app.Activity val$activity;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.GvrUiLayoutImpl$CloseButtonListenerWrapper {
-  void run();
-  void setClientCloseButtonListener(java.lang.Runnable);
-  java.lang.Runnable defaultCloseButtonListener;
-   <init>(android.content.Context, java.lang.Runnable, com.google.vr.ndk.base.DaydreamUtilsWrapper);
-  boolean invokingCloseButton;
-  java.lang.Runnable activeCloseButtonListener;
-  android.content.Context context;
-  java.lang.Runnable passiveCloseButtonListener;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.Properties {
-   <init>(long);
-  long nativeProperties;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.SdkConfigurationReader {
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams sParams;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams getParams(android.content.Context);
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams readParamsFromProvider(com.google.vr.cardboard.VrParamsProvider);
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams DEFAULT_PARAMS;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams REQUESTED_PARAMS;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.SdkDaydreamTouchListener {
-   <init>(com.google.vr.ndk.base.GvrLayoutImpl);
-  boolean isDaydreamImageAlignmentEnabled;
-  void setDeviceParams(com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams);
-  com.google.vr.ndk.base.GvrApi gvrApi;
-  com.google.vr.cardboard.VrParamsProvider vrParamsProvider;
-  com.google.vr.ndk.base.GvrLayoutImpl gvrLayout;
-  void initWithDisplayParams(android.util.DisplayMetrics, com.google.vr.sdk.proto.nano.Display$DisplayParams);
-  void shutdown();
-  void refreshViewerProfile();
-  void setEnabled(boolean);
-  void access$300(com.google.vr.ndk.base.SdkDaydreamTouchListener, android.util.DisplayMetrics, com.google.vr.sdk.proto.nano.Display$DisplayParams);
-  com.google.vr.cardboard.VrParamsProvider access$200(com.google.vr.ndk.base.SdkDaydreamTouchListener);
-  boolean handleTouch(android.view.MotionEvent, float, float);
-  void init(android.util.DisplayMetrics, com.google.vr.sdk.proto.nano.Display$DisplayParams);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.SdkDaydreamTouchListener$FinishInitilizationTask {
-  android.os.AsyncTask execute(java.lang.Object[]);
-   <init>(com.google.vr.ndk.base.SdkDaydreamTouchListener, com.google.vr.ndk.base.SdkDaydreamTouchListener$1);
-  com.google.vr.sdk.proto.nano.Display$DisplayParams doInBackground(java.lang.Void[]);
-   <init>(com.google.vr.ndk.base.SdkDaydreamTouchListener);
-  com.google.vr.ndk.base.SdkDaydreamTouchListener this$0;
-  void onProgressUpdate(java.lang.Void[]);
-  android.view.Display display;
-  void onPostExecute(com.google.vr.sdk.proto.nano.Display$DisplayParams);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.SdkDaydreamTouchListener$RefreshViewerProfileTask {
-  void onProgressUpdate(java.lang.Void[]);
-   <init>(com.google.vr.ndk.base.SdkDaydreamTouchListener);
-  void onPostExecute(com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams);
-  com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams doInBackground(java.lang.Void[]);
-  android.os.AsyncTask execute(java.lang.Object[]);
-  com.google.vr.ndk.base.SdkDaydreamTouchListener this$0;
-   <init>(com.google.vr.ndk.base.SdkDaydreamTouchListener, com.google.vr.ndk.base.SdkDaydreamTouchListener$1);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.SwapChain {
-  void shutdown();
-   <init>(long);
-  int currentFrame;
-  com.google.vr.ndk.base.Frame[] frames;
-  long nativeSwapChain;
-  java.lang.String TAG;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ThrottlingMonitor {
-  com.google.vr.vrcore.performance.api.IPerformanceService perfService;
-  android.os.Handler mainHandler;
-  java.lang.Object access$000(com.google.vr.ndk.base.ThrottlingMonitor);
-  java.lang.Object lock;
-  android.content.Context context;
-  int addTriggerInternal(android.content.ComponentName, int, float, com.google.vr.ndk.base.ThrottlingMonitor$TemperatureTrigger, long, android.os.Handler);
-  android.content.ServiceConnection connection;
-  com.google.vr.vrcore.performance.api.IPerformanceService access$102(com.google.vr.ndk.base.ThrottlingMonitor, com.google.vr.vrcore.performance.api.IPerformanceService);
-  java.util.ArrayList access$200(com.google.vr.ndk.base.ThrottlingMonitor);
-  java.util.ArrayList setupCallbacks;
-   <init>(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ThrottlingMonitor$1 {
-   <init>(com.google.vr.ndk.base.ThrottlingMonitor);
-  com.google.vr.ndk.base.ThrottlingMonitor this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ThrottlingMonitor$2 {
-  com.google.vr.ndk.base.ThrottlingMonitor$SetupCallback val$callback;
-   <init>(com.google.vr.ndk.base.ThrottlingMonitor, com.google.vr.ndk.base.ThrottlingMonitor$SetupCallback);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ThrottlingMonitor$SetupCallback {
-  void onInitialized();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ThrottlingMonitor$TemperatureTrigger {
-  void onTemperatureEvent(float, long);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ThrottlingMonitor$ThrottlingTriggerCallback {
-  com.google.vr.ndk.base.ThrottlingMonitor$TemperatureTrigger trigger;
-  com.google.vr.ndk.base.ThrottlingMonitor$TemperatureTrigger access$300(com.google.vr.ndk.base.ThrottlingMonitor$ThrottlingTriggerCallback);
-   <init>(com.google.vr.ndk.base.ThrottlingMonitor$TemperatureTrigger, android.os.Handler);
-  android.os.Handler handler;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.ThrottlingMonitor$ThrottlingTriggerCallback$1 {
-   <init>(com.google.vr.ndk.base.ThrottlingMonitor$ThrottlingTriggerCallback, float, long);
-  float val$temperature;
-  long val$timeRemaining;
-  com.google.vr.ndk.base.ThrottlingMonitor$ThrottlingTriggerCallback this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.TraceCompat {
-  void endSection();
-  void beginSection(java.lang.String);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.UserPrefs {
-   <init>(long);
-  long nativeUserPrefs;
-  java.lang.String TAG;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.Value {
-  void close();
-  long nativeValue;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.Version {
-   <init>(int, int, int);
-  com.google.vr.ndk.base.Version parse(java.lang.String);
-  java.lang.String toString();
-  int minorVersion;
-  boolean isAtLeast(com.google.vr.ndk.base.Version);
-  com.google.vr.ndk.base.Version CURRENT;
-  int patchVersion;
-  com.google.vr.ndk.base.Version MIN;
-  int majorVersion;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.VrCoreSdkClient {
-  com.google.vr.vrcore.common.api.IDaydreamManager access$200(com.google.vr.ndk.base.VrCoreSdkClient);
-  boolean access$900(com.google.vr.ndk.base.VrCoreSdkClient);
-  void onPause();
-  void handleNoDaydreamManager();
-  com.google.vr.vrcore.logging.api.IVrCoreLoggingService access$1102(com.google.vr.ndk.base.VrCoreSdkClient, com.google.vr.vrcore.logging.api.IVrCoreLoggingService);
-  void resumeTracking(com.google.vr.ndk.base.GvrApi, com.google.vr.vrcore.common.api.HeadTrackingState);
-  com.google.vr.vrcore.common.api.IVrCoreSdkService access$102(com.google.vr.ndk.base.VrCoreSdkClient, com.google.vr.vrcore.common.api.IVrCoreSdkService);
-  com.google.vr.ndk.base.FadeOverlayView fadeOverlayView;
-  android.content.Context context;
-  void setReentryIntent(android.app.PendingIntent);
-  android.app.AlertDialog helpCenterDialog;
-  void warnIfIncompatibleClient();
-  void access$1400(com.google.vr.ndk.base.GvrApi, com.google.vr.vrcore.common.api.HeadTrackingState);
-  void access$000(com.google.vr.ndk.base.VrCoreSdkClient);
-  android.content.ComponentName access$400(com.google.vr.ndk.base.VrCoreSdkClient);
-  void setOnDonNotNeededListener(java.lang.Runnable);
-  com.google.vr.vrcore.common.api.IVrCoreSdkService access$100(com.google.vr.ndk.base.VrCoreSdkClient);
-  int prepareVr(com.google.vr.vrcore.common.api.HeadTrackingState);
-  java.lang.Runnable access$700(com.google.vr.ndk.base.VrCoreSdkClient);
-  com.google.vr.ndk.base.DaydreamUtilsWrapper daydreamUtils;
-  int access$600(com.google.vr.ndk.base.VrCoreSdkClient, com.google.vr.vrcore.common.api.HeadTrackingState);
-  void handleBindFailed();
-  java.lang.Runnable onDonNotNeededListener;
-  boolean isEnabled;
-  int vrCoreClientApiVersion;
-  void resumeTracking(com.google.vr.vrcore.common.api.HeadTrackingState);
-  android.content.ServiceConnection serviceConnection;
-  com.google.vr.vrcore.logging.api.IVrCoreLoggingService loggingService;
-   <init>(android.content.Context, com.google.vr.ndk.base.GvrApi, android.content.ComponentName, com.google.vr.ndk.base.DaydreamUtilsWrapper, java.lang.Runnable, com.google.vr.ndk.base.FadeOverlayView);
-  android.app.PendingIntent optionalReentryIntent;
-  com.google.vr.ndk.base.VrCoreSdkClient$DaydreamListenerImpl daydreamListener;
-  boolean onResume();
-  void handlePrepareVrFailed();
-  android.content.ComponentName componentName;
-  com.google.vr.vrcore.common.api.IVrCoreSdkService vrCoreSdkService;
-  com.google.vr.ndk.base.VrCoreSdkClient$DaydreamListenerImpl access$500(com.google.vr.ndk.base.VrCoreSdkClient);
-  boolean doBind();
-  com.google.vr.vrcore.logging.api.IVrCoreLoggingService getLoggingService();
-  boolean hasCompatibleSdkService(android.content.Context);
-  boolean isResumed;
-  boolean shouldBind;
-  void access$800(com.google.vr.ndk.base.VrCoreSdkClient);
-  boolean isBound;
-  com.google.vr.vrcore.common.api.HeadTrackingState getHeadTrackingState();
-  com.google.vr.ndk.base.GvrApi gvrApi;
-  com.google.vr.vrcore.common.api.IDaydreamManager daydreamManager;
-  com.google.vr.vrcore.common.api.IDaydreamManager access$202(com.google.vr.ndk.base.VrCoreSdkClient, com.google.vr.vrcore.common.api.IDaydreamManager);
-  void setEnabled(boolean);
-  void onExitingFromVr();
-  java.lang.Runnable closeVrRunnable;
-  void access$1000(com.google.vr.ndk.base.VrCoreSdkClient, com.google.vr.vrcore.common.api.HeadTrackingState);
-  void access$300(com.google.vr.ndk.base.VrCoreSdkClient);
-  void doUnbind();
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.VrCoreSdkClient$1 {
-   <init>(com.google.vr.ndk.base.VrCoreSdkClient);
-  com.google.vr.ndk.base.VrCoreSdkClient this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.VrCoreSdkClient$DaydreamListenerImpl {
-  void cancelSafeguard(int);
-  java.lang.ref.WeakReference closeVrRunnableWeak;
-  void resetSafeguards();
-   <init>(com.google.vr.ndk.base.GvrApi, com.google.vr.ndk.base.FadeOverlayView, java.lang.Runnable);
-  void access$1200(com.google.vr.ndk.base.VrCoreSdkClient$DaydreamListenerImpl, int, long, int);
-  java.lang.ref.WeakReference fadeOverlayViewWeak;
-  void rescheduleSafeguard(int, long);
-  void applyColorfulFadeImpl(int, long, int);
-  java.lang.ref.WeakReference gvrApiWeak;
-  void access$1300(com.google.vr.ndk.base.VrCoreSdkClient$DaydreamListenerImpl, com.google.vr.vrcore.common.api.HeadTrackingState);
-  android.os.Handler safeguardHandler;
-  void resumeHeadTrackingImpl(com.google.vr.vrcore.common.api.HeadTrackingState);
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.VrCoreSdkClient$DaydreamListenerImpl$1 {
-   <init>(com.google.vr.ndk.base.VrCoreSdkClient$DaydreamListenerImpl);
-  com.google.vr.ndk.base.VrCoreSdkClient$DaydreamListenerImpl this$0;
-}
-
--keep,allowobfuscation class com.google.vr.ndk.base.VrCoreSdkClient$DaydreamListenerImpl$2 {
-  int val$color;
-  long val$durationMillis;
-   <init>(com.google.vr.ndk.base.VrCoreSdkClient$DaydreamListenerImpl, com.google.vr.ndk.base.FadeOverlayView, int, long, int);
-  com.google.vr.ndk.base.FadeOverlayView val$fadeOverlayView;
-  int val$fadeType;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.common.deps.a {
-  java.lang.String mDescriptor;
-  android.os.IBinder mRemote;
-   <init>(android.os.IBinder, java.lang.String);
-}
-
--keep,allowobfuscation class com.google.vr.sdk.common.deps.b {
-   <init>();
-  java.lang.String getInterfaceDescriptor();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.common.deps.c {
-  void a(android.os.Parcel, android.os.Parcelable);
-  boolean a(android.os.Parcel);
-  android.os.Parcelable a(android.os.Parcel, android.os.Parcelable$Creator);
-  void a(android.os.Parcel, android.os.IInterface);
-  void b(android.os.Parcel, android.os.Parcelable);
-  void a(android.os.Parcel, boolean);
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Analytics$AnalyticsRequest {
-  com.google.vr.sdk.proto.nano.Analytics$AnalyticsRequest clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-   <init>();
-  com.google.vr.sdk.proto.nano.Analytics$AnalyticsRequest[] _emptyArray;
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.Analytics$AnalyticsRequest clone();
-  com.google.vr.sdk.proto.nano.Analytics$AnalyticsRequest mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  long prevSampleTimestampNanoseconds_;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Analytics$AnalyticsSample {
-  com.google.vr.sdk.proto.nano.Analytics$AnalyticsSample[] _emptyArray;
-  com.google.vr.sdk.proto.nano.Analytics$AnalyticsSample clone();
-  long timestampNanoseconds_;
-  int cachedSize;
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics appAnalytics;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics asyncReprojectionAnalytics;
-  com.google.vr.sdk.proto.nano.Analytics$AnalyticsSample mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-  com.google.vr.sdk.proto.nano.Analytics$AnalyticsSample clear();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Analytics$AppAnalytics {
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics clone();
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics$SubmitStatus[] submitStatus;
-  float fps_;
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics[] _emptyArray;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-   <init>();
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics clear();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Analytics$AppAnalytics$SubmitStatus {
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics$SubmitStatus[] _emptyArray;
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics$SubmitStatus clear();
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics$SubmitStatus clone();
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics$SubmitStatus[] emptyArray();
-  long timestampNanoseconds_;
-  int bitField0_;
-  boolean wasBlockedOnGpu_;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.Analytics$AppAnalytics$SubmitStatus mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics {
-  int bitField0_;
-   <init>();
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus[] vsyncStatus;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics[] _emptyArray;
-  float fps_;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics clone();
-  int totalMissedVsyncs_;
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics clear();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus {
-  int oneof_Status_;
-   <init>();
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$NewAppFrame newAppFrame;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus[] _emptyArray;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus clone();
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$MissedVsync missedVsync;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus clear();
-  int bitField0_;
-  long timestampNanoseconds_;
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$ReusedAppFrame reusedAppFrame;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus[] emptyArray();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$MissedVsync {
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$MissedVsync mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$MissedVsync clone();
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$MissedVsync[] _emptyArray;
-   <init>();
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$MissedVsync clear();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$NewAppFrame {
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$NewAppFrame clear();
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$NewAppFrame mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  long sinceSubmitNanoseconds_;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$NewAppFrame[] _emptyArray;
-  int numSkippedAppFrames_;
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$NewAppFrame clone();
-  int cachedSize;
-   <init>();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$ReusedAppFrame {
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$ReusedAppFrame clone();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$ReusedAppFrame mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-  long sinceSubmitNanoseconds_;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$ReusedAppFrame[] _emptyArray;
-  com.google.vr.sdk.proto.nano.Analytics$AsyncReprojectionAnalytics$VsyncStatus$ReusedAppFrame clear();
-  int bitField0_;
-  int cachedSize;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.CardboardDevice$CardboardInternalParams {
-  int checkOrientationTypeOrThrow(int);
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  java.lang.String gyroscope_;
-  com.google.vr.sdk.proto.nano.CardboardDevice$CardboardInternalParams clone();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.String accelerometer_;
-  com.google.vr.sdk.proto.nano.CardboardDevice$CardboardInternalParams mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-  float yPpiOverride_;
-  int[] eyeOrientations;
-  float screenCenterToLensDistance_;
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.CardboardDevice$CardboardInternalParams[] _emptyArray;
-  float xPpiOverride_;
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.CardboardDevice$CardboardInternalParams clear();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.CardboardDevice$DaydreamInternalParams {
-  int distortionMeshResolution_;
-  boolean sensorOrientationIndependentOfDisplay_;
-  com.google.vr.sdk.proto.nano.CardboardDevice$DaydreamInternalParams clone();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.sdk.proto.nano.CardboardDevice$DaydreamInternalParams mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int version_;
-   <init>();
-  com.google.vr.sdk.proto.nano.CardboardDevice$DaydreamInternalParams[] _emptyArray;
-  com.google.vr.sdk.proto.nano.CardboardDevice$VignetteParams vignetteParams;
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.CardboardDevice$ScreenAlignmentMarker[] alignmentMarkers;
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.CardboardDevice$DaydreamInternalParams clear();
-  boolean clipFieldOfViewToDisplay_;
-  boolean getUseRotationalAlignmentCorrection();
-  boolean useRotationalAlignmentCorrection_;
-  boolean clampDistortionToMaximumFieldOfView_;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams {
-   <init>();
-  int primaryButton_;
-  boolean hasMagnet_;
-  java.lang.String getVendor();
-  int cachedSize;
-  float trayToLensDistance_;
-  com.google.vr.sdk.proto.nano.CardboardDevice$DaydreamInternalParams daydreamInternal;
-  float[] distortionCoefficients;
-  java.lang.String vendor_;
-  java.lang.String model_;
-  float[] greenDistortionCoefficients;
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams clear();
-  int verticalAlignment_;
-  float getTrayToLensDistance();
-  float[] leftEyeFieldOfViewAngles;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams[] _emptyArray;
-  com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int checkVerticalAlignmentTypeOrThrow(int);
-  com.google.vr.sdk.proto.nano.CardboardDevice$DeviceParams clone();
-  float[] blueDistortionCoefficients;
-  float screenToLensDistance_;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  float interLensDistance_;
-  com.google.vr.sdk.proto.nano.CardboardDevice$CardboardInternalParams internal;
-  java.lang.String getModel();
-  int checkButtonTypeOrThrow(int);
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.CardboardDevice$ScreenAlignmentMarker {
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.sdk.proto.nano.CardboardDevice$ScreenAlignmentMarker mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  float getVertical();
-  com.google.vr.sdk.proto.nano.CardboardDevice$ScreenAlignmentMarker clone();
-  com.google.vr.sdk.proto.nano.CardboardDevice$ScreenAlignmentMarker clear();
-   <init>();
-  com.google.vr.sdk.proto.nano.CardboardDevice$ScreenAlignmentMarker[] emptyArray();
-  float vertical_;
-  float getHorizontal();
-  com.google.vr.sdk.proto.nano.CardboardDevice$ScreenAlignmentMarker[] _emptyArray;
-  int cachedSize;
-  float horizontal_;
-  int bitField0_;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.CardboardDevice$VignetteParams {
-  com.google.vr.sdk.proto.nano.CardboardDevice$VignetteParams clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.sdk.proto.nano.CardboardDevice$VignetteParams mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-   <init>();
-  int condition_;
-  float value_;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  int checkVignetteParamsConditionOrThrow(int);
-  com.google.vr.sdk.proto.nano.CardboardDevice$VignetteParams clone();
-  int cachedSize;
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.CardboardDevice$VignetteParams[] _emptyArray;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Display$DisplayParams {
-  float bottomBezelHeight_;
-  float xPpi_;
-  float yPpi_;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.Display$DisplayParams[] _emptyArray;
-  com.google.vr.sdk.proto.nano.Display$DisplayParams clone();
-   <init>();
-  com.google.vr.sdk.proto.nano.Display$DisplayParams clear();
-  com.google.vr.sdk.proto.nano.Display$DisplayParams setXPpi(float);
-  boolean hasXPpi();
-  float[] dEPRECATEDGyroBias;
-  float getYPpi();
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.Display$DisplayParams mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  float getXPpi();
-  com.google.vr.sdk.proto.nano.Display$DisplayParams setYPpi(float);
-  boolean hasBottomBezelHeight();
-  float getBottomBezelHeight();
-  boolean hasYPpi();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Preferences$DeveloperPrefs {
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  boolean getOpenglKhrDebugEnabled();
-  int checkMotophoPatchModeOrThrow(int);
-  boolean developerLoggingEnabled_;
-  boolean dEPRECATEDHeadTrackingServiceEnabled_;
-  com.google.vr.sdk.proto.nano.Preferences$DeveloperPrefs[] _emptyArray;
-  int motophoPatchMode_;
-  boolean captureEnabled_;
-  boolean dEPRECATEDGvrPlatformLibraryEnabled_;
-  boolean sensorLoggingEnabled_;
-  int cachedSize;
-  boolean performanceMonitoringEnabled_;
-  com.google.vr.sdk.proto.nano.Preferences$DeveloperPrefs clear();
-   <init>();
-  boolean openglKhrDebugEnabled_;
-  boolean forceUndistortedRendering_;
-  com.google.vr.sdk.proto.nano.Preferences$DeveloperPrefs clone();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int bitField0_;
-  boolean dEPRECATEDMotophoPatchEnabled_;
-  boolean performanceLoggingActivated_;
-  com.google.vr.sdk.proto.nano.Preferences$DeveloperPrefs mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  boolean performanceHudEnabled_;
-  boolean frameTrackerEnabled_;
-  com.google.vr.sdk.proto.nano.Preferences$SafetyCylinderParams safetyCylinderParams;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Preferences$FrameReuseMonitoringParams {
-  com.google.vr.sdk.proto.nano.Preferences$FrameReuseMonitoringParams clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  long frameWindowMs_;
-  float failureProportion_;
-  com.google.vr.sdk.proto.nano.Preferences$FrameReuseMonitoringParams[] _emptyArray;
-  int bitField0_;
-  int cachedSize;
-  float recoveryProportion_;
-  long fadeInDurationMs_;
-  com.google.vr.sdk.proto.nano.Preferences$FrameReuseMonitoringParams clone();
-   <init>();
-  long promptUserToKillDelayMs_;
-  long fadeOutDurationMs_;
-  com.google.vr.sdk.proto.nano.Preferences$FrameReuseMonitoringParams mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Preferences$SafetyCylinderParams {
-  com.google.vr.sdk.proto.nano.Preferences$SafetyCylinderParams clone();
-  float anchorWarningDistance_;
-  com.google.vr.sdk.proto.nano.Preferences$SafetyCylinderParams mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  boolean graphicsEnabled_;
-  float[] outerFogColor;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  float collisionSphereRadius_;
-  int bitField0_;
-  float innerRadius_;
-  float outerRadius_;
-  int cachedSize;
-  float enterEventRadius_;
-   <init>();
-  float[] innerFogColor;
-  float exitEventRadius_;
-  com.google.vr.sdk.proto.nano.Preferences$SafetyCylinderParams[] _emptyArray;
-  com.google.vr.sdk.proto.nano.Preferences$SafetyCylinderParams clear();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Preferences$UserPrefs {
-  int controllerHandedness_;
-  int bitField0_;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-  com.google.vr.sdk.proto.nano.Preferences$UserPrefs mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.vr.sdk.proto.nano.Preferences$UserPrefs[] _emptyArray;
-   <init>();
-  com.google.vr.sdk.proto.nano.Preferences$UserPrefs clone();
-  com.google.vr.sdk.proto.nano.Preferences$UserPrefs clear();
-  com.google.vr.sdk.proto.nano.Preferences$DeveloperPrefs developerPrefs;
-  int cachedSize;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int checkHandednessOrThrow(int);
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.SdkConfiguration$SdkConfigurationRequest {
-   <init>();
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.SdkConfiguration$SdkConfigurationRequest clear();
-  com.google.vr.sdk.proto.nano.SdkConfiguration$SdkConfigurationRequest[] _emptyArray;
-  com.google.common.logging.nano.Vr$VREvent$SdkConfigurationParams requestedParams;
-  com.google.vr.sdk.proto.nano.SdkConfiguration$SdkConfigurationRequest mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  java.lang.String sdkVersion;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.sdk.proto.nano.SdkConfiguration$SdkConfigurationRequest clone();
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Session$HeadTrackingServiceState {
-  com.google.vr.sdk.proto.nano.Session$HeadTrackingServiceState clone();
-  int bitField0_;
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.Session$HeadTrackingServiceState clear();
-   <init>();
-  boolean applyDisplayFromSensorRotation_;
-  com.google.vr.sdk.proto.nano.Session$RecenteredState recenteredState;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.sdk.proto.nano.Session$HeadTrackingServiceState mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.vr.sdk.proto.nano.Session$SafeRegionState safeRegionState;
-  com.google.vr.sdk.proto.nano.Session$HeadTrackingServiceState[] _emptyArray;
-  float defaultFloorHeight_;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Session$Pose {
-  float[] p;
-  com.google.vr.sdk.proto.nano.Session$Pose mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-   <init>();
-  com.google.vr.sdk.proto.nano.Session$Pose clone();
-  com.google.vr.sdk.proto.nano.Session$Pose clear();
-  float[] q;
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.Session$Pose[] _emptyArray;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Session$RecenteredState {
-  com.google.vr.sdk.proto.nano.Session$RecenteredState[] _emptyArray;
-  boolean storeUnknownField(com.google.protobuf.nano.CodedInputByteBufferNano, int);
-   <init>();
-  com.google.vr.sdk.proto.nano.Session$Pose headRecenterPoseInTrackingSpace;
-  int cachedSize;
-  com.google.vr.sdk.proto.nano.Session$RecenteredState clear();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  boolean applyDisplayFromSensorRotation_;
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.Session$RecenteredState mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.vr.sdk.proto.nano.Session$RecenteredState clone();
-  int checkTypeOrThrow(int);
-  long timestampNs_;
-  int type_;
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Session$SafeRegionState {
-  boolean inside_;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-  long counter_;
-  com.google.vr.sdk.proto.nano.Session$SafeRegionState clone();
-  com.google.vr.sdk.proto.nano.Session$SafeRegionState clear();
-  int bitField0_;
-  com.google.vr.sdk.proto.nano.Session$SafeRegionState[] _emptyArray;
-   <init>();
-  com.google.vr.sdk.proto.nano.Session$SafeRegionState mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-}
-
--keep,allowobfuscation class com.google.vr.sdk.proto.nano.Session$TrackerState {
-  double[] magnetometerBias;
-  com.google.vr.sdk.proto.nano.Session$TrackerState[] _emptyArray;
-  long timeSinceEpochSeconds_;
-  long magCalibrationTimeSinceEpochSeconds_;
-   <init>();
-  boolean trackingInVrcore_;
-  double[] gyroscopeBias;
-  float[] lensOffset;
-  float[] rightLensOffset;
-  com.google.vr.sdk.proto.nano.Session$TrackerState mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  com.google.vr.sdk.proto.nano.Session$TrackerState clone();
-  double[] lastGyroscopeSample;
-  com.google.vr.sdk.proto.nano.Session$TrackerState clear();
-  double[] q;
-  double magneticFieldStrength_;
-  double lastGyroscopeTimestamp_;
-  int bitField0_;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int cachedSize;
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.base.api.BuildUtils {
-  java.lang.Boolean isDebug;
-  boolean isDebugBuild(android.content.Context);
-  boolean computeIsDebugBuild(android.content.Context);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.base.api.ParcelableProto {
-  boolean shouldSerializeEmptyInsteadOfNullBuffer();
-   <init>(byte[]);
-  boolean isEmpty();
-  byte[] data;
-  void readFromParcel(android.os.Parcel);
-  int getSizeBytes();
-   <init>();
-  java.lang.String TAG;
-  void setFromProto(com.google.protobuf.nano.MessageNano);
-  void clear();
-  void setData(byte[]);
-  boolean shouldSerializeDataLength();
-   <init>(android.os.Parcel);
-   <init>(com.google.protobuf.nano.MessageNano);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.base.api.SignatureUtils {
-  android.content.pm.Signature VRCORE_DEBUG_SIGNATURE;
-  android.content.pm.Signature VRCORE_RELEASE_SIGNATURE;
-  android.content.pm.Signature KEYBOARD_RELEASE_SIGNATURE;
-  android.content.pm.Signature KEYBOARD_DEBUG_SIGNATURE;
-  android.content.pm.Signature BLAZE_DEBUG_SIGNATURE;
-  android.content.pm.Signature signatureFromBase64(java.lang.String);
-  android.content.pm.Signature ANDROID_DEBUG_SIGNATURE;
-  boolean verifySignature(android.content.pm.PackageInfo, android.content.pm.Signature[]);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.base.api.VrCoreNotAvailableException {
-  int errorCode;
-   <init>(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.base.api.VrCoreUtils {
-  int getVrCoreClientApiVersion(android.content.Context);
-  java.lang.String getConnectionResultString(int);
-  java.lang.String getVrCoreSdkLibraryVersion(android.content.Context);
-  int checkVrCoreAvailability(android.content.Context);
-  boolean isVrCorePackage(java.lang.String);
-  int checkVrCoreAvailabilityImpl(android.content.Context);
-  boolean verifyRemotePackageSignature(android.content.Context);
-  java.lang.String TAG;
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.HeadTrackingServiceState {
-   <init>(android.os.Parcel, com.google.vr.vrcore.common.api.HeadTrackingServiceState$1);
-  byte[] getData();
-   <init>(android.os.Parcel);
-  int getSizeBytes();
-  android.os.Parcelable$Creator CREATOR;
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.HeadTrackingServiceState$1 {
-   <init>();
-  com.google.vr.vrcore.common.api.HeadTrackingServiceState createFromParcel(android.os.Parcel);
-  com.google.vr.vrcore.common.api.HeadTrackingServiceState[] newArray(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.HeadTrackingState {
-  byte[] getData();
-   <init>();
-   <init>(android.os.Parcel);
-  boolean isEmpty();
-  int getSizeBytes();
-   <init>(byte[]);
-  void readFromParcel(android.os.Parcel);
-   <init>(android.os.Parcel, com.google.vr.vrcore.common.api.HeadTrackingState$1);
-  android.os.Parcelable$Creator CREATOR;
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.HeadTrackingState$1 {
-   <init>();
-  com.google.vr.vrcore.common.api.HeadTrackingState createFromParcel(android.os.Parcel);
-  com.google.vr.vrcore.common.api.HeadTrackingState[] newArray(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IDaydreamListener$Stub {
-  void setLensOffset(float, float, float);
-  void applyFade(int, long);
-  void recenterHeadTracking();
-   <init>();
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-  int getTargetApiVersion();
-  com.google.vr.vrcore.common.api.IDaydreamListener asInterface(android.os.IBinder);
-  void resumeHeadTracking(com.google.vr.vrcore.common.api.HeadTrackingState);
-  void applyColorfulFade(int, long, int);
-  void invokeCloseAction();
-  void deprecated_setLensOffsets(float, float, float, float);
-  void attachInterface(android.os.IInterface, java.lang.String);
-  com.google.vr.vrcore.common.api.HeadTrackingState requestStopTracking();
-  void dumpDebugData();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IDaydreamListener$Stub$Proxy {
-  android.os.Parcel obtainAndWriteInterfaceToken();
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-  void transactOneway(int, android.os.Parcel);
-   <init>(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IDaydreamManager {
-  void handleInsertionIntoHeadset(byte[]);
-  int prepareVr(android.content.ComponentName, com.google.vr.vrcore.common.api.HeadTrackingState);
-  void handleRemovalFromHeadset();
-  boolean launchVrTransition(com.google.vr.vrcore.common.api.ITransitionCallbacks);
-  int prepareVr2(android.content.ComponentName, int, android.app.PendingIntent, com.google.vr.vrcore.common.api.HeadTrackingState);
-  boolean launchInVr(android.app.PendingIntent, android.content.ComponentName);
-  boolean unregisterListener(android.content.ComponentName);
-  boolean launchVrHome();
-  void onExitingFromVr();
-  void unregisterDaydreamIntent();
-  void registerDaydreamIntent(android.app.PendingIntent);
-  int prepareVr3(android.os.Bundle, com.google.vr.vrcore.common.api.HeadTrackingState);
-  boolean registerListener(android.content.ComponentName, com.google.vr.vrcore.common.api.IDaydreamListener);
-  boolean exitFromVr(android.app.PendingIntent);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IDaydreamManager$Stub {
-  boolean registerListener(android.content.ComponentName, com.google.vr.vrcore.common.api.IDaydreamListener);
-  com.google.vr.vrcore.common.api.IDaydreamManager asInterface(android.os.IBinder);
-  boolean launchVrTransition(com.google.vr.vrcore.common.api.ITransitionCallbacks);
-  int prepareVr(android.content.ComponentName, com.google.vr.vrcore.common.api.HeadTrackingState);
-  void attachInterface(android.os.IInterface, java.lang.String);
-  boolean launchInVr(android.app.PendingIntent, android.content.ComponentName);
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-  boolean unregisterListener(android.content.ComponentName);
-  int prepareVr2(android.content.ComponentName, int, android.app.PendingIntent, com.google.vr.vrcore.common.api.HeadTrackingState);
-  boolean launchVrHome();
-  int prepareVr3(android.os.Bundle, com.google.vr.vrcore.common.api.HeadTrackingState);
-  boolean exitFromVr(android.app.PendingIntent);
-  void onExitingFromVr();
-  void launchVrTransition2(android.os.Bundle);
-  void registerDaydreamIntent(android.app.PendingIntent);
-  boolean deprecatedLaunchInVr(android.app.PendingIntent);
-  void handleRemovalFromHeadset();
-  void handleInsertionIntoHeadset(byte[]);
-  void unregisterDaydreamIntent();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IDaydreamManager$Stub$Proxy {
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-   <init>(android.os.IBinder);
-  void transactOneway(int, android.os.Parcel);
-  android.os.Parcel obtainAndWriteInterfaceToken();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.ITransitionCallbacks {
-  void onTransitionComplete();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.ITransitionCallbacks$Stub {
-  void attachInterface(android.os.IInterface, java.lang.String);
-  com.google.vr.vrcore.common.api.ITransitionCallbacks asInterface(android.os.IBinder);
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-   <init>();
-  void onTransitionComplete();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.ITransitionCallbacks$Stub$Proxy {
-  android.os.Parcel obtainAndWriteInterfaceToken();
-  void transactOneway(int, android.os.Parcel);
-   <init>(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IVrCoreSdkService {
-  boolean setClientOptions(android.content.ComponentName, android.os.Bundle);
-  boolean initialize(int);
-  com.google.vr.vrcore.logging.api.IVrCoreLoggingService getLoggingService();
-  com.google.vr.vrcore.common.api.IDaydreamManager getDaydreamManager();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IVrCoreSdkService$Stub {
-  com.google.vr.vrcore.common.api.IVrCoreSdkService asInterface(android.os.IBinder);
-  boolean initialize(int);
-  com.google.vr.vrcore.common.api.IDaydreamManager getDaydreamManager();
-  com.google.vr.vrcore.logging.api.IVrCoreLoggingService getLoggingService();
-  void attachInterface(android.os.IInterface, java.lang.String);
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-  boolean setClientOptions(android.content.ComponentName, android.os.Bundle);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.common.api.IVrCoreSdkService$Stub$Proxy {
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-  android.os.Parcel obtainAndWriteInterfaceToken();
-   <init>(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerAccelEvent {
-  int getByteSize();
-   <init>();
-  void writeToParcel(android.os.Parcel, int);
-  android.os.Parcelable$Creator CREATOR;
-  int controllerId;
-  float y;
-  float x;
-  void readFromParcel(android.os.Parcel);
-  float z;
-  long timestampNanos;
-   <init>(android.os.Parcel);
-  void copyFrom(com.google.vr.vrcore.controller.api.ControllerEvent);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerAccelEvent$1 {
-   <init>();
-  com.google.vr.vrcore.controller.api.ControllerAccelEvent createFromParcel(android.os.Parcel);
-  com.google.vr.vrcore.controller.api.ControllerAccelEvent[] newArray(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerBatteryEvent {
-   <init>();
-   <init>(android.os.Parcel);
-  void writeToParcel(android.os.Parcel, int);
-  void copyFrom(com.google.vr.vrcore.controller.api.ControllerEvent);
-  void readFromParcel(android.os.Parcel);
-  android.os.Parcelable$Creator CREATOR;
-  long timestampNanos;
-  int getByteSize();
-  int controllerId;
-  boolean charging;
-  int batteryLevelBucket;
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerBatteryEvent$1 {
-   <init>();
-  com.google.vr.vrcore.controller.api.ControllerBatteryEvent createFromParcel(android.os.Parcel);
-  com.google.vr.vrcore.controller.api.ControllerBatteryEvent[] newArray(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerButtonEvent {
-  int controllerId;
-  long timestampNanos;
-  boolean down;
-  int getByteSize();
-  int[] ALL_BUTTONS;
-   <init>(android.os.Parcel);
-  void writeToParcel(android.os.Parcel, int);
-   <init>();
-  void readFromParcel(android.os.Parcel);
-  int button;
-  android.os.Parcelable$Creator CREATOR;
-  void copyFrom(com.google.vr.vrcore.controller.api.ControllerEvent);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerButtonEvent$1 {
-   <init>();
-  com.google.vr.vrcore.controller.api.ControllerButtonEvent createFromParcel(android.os.Parcel);
-  com.google.vr.vrcore.controller.api.ControllerButtonEvent[] newArray(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerEvent {
-   <init>();
-  void copyFrom(com.google.vr.vrcore.controller.api.ControllerEvent);
-  int controllerId;
-  void writeToParcel(android.os.Parcel, int);
-  void readFromParcel(android.os.Parcel);
-  long timestampNanos;
-  int getByteSize();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerEventPacket {
-  void readFromParcel(android.os.Parcel);
-  java.lang.Object poolLock;
-  com.google.vr.vrcore.controller.api.ControllerButtonEvent[] buttonEvents;
-  void recycle();
-  com.google.vr.vrcore.controller.api.ControllerOrientationEvent getOrientationEvent(int);
-  com.google.vr.vrcore.controller.api.ControllerTouchEvent getTouchEvent(int);
-  int touchEventCount;
-  void clear();
-  int buttonEventCount;
-  int getGyroEventCount();
-  int getAccelEventCount();
-  void setEventsControllerIndex(int);
-  void writeToParcel(android.os.Parcel, int);
-  int calculateParcelByteLength();
-  com.google.vr.vrcore.controller.api.ControllerGyroEvent[] gyroEvents;
-  com.google.vr.vrcore.controller.api.ControllerOrientationEvent[] orientationEvents;
-  int gyroEventCount;
-  com.google.vr.vrcore.controller.api.ControllerTouchEvent[] touchEvents;
-  int orientationEventCount;
-  com.google.vr.vrcore.controller.api.ControllerAccelEvent[] accelEvents;
-  java.util.ArrayDeque pool;
-  int getTouchEventCount();
-  android.os.Parcelable$Creator CREATOR;
-   <init>();
-  com.google.vr.vrcore.controller.api.ControllerGyroEvent getGyroEvent(int);
-  void setControllerIndex(int, int, com.google.vr.vrcore.controller.api.ControllerEvent[]);
-  int accelEventCount;
-  void copyFrom(com.google.vr.vrcore.controller.api.ControllerEventPacket);
-  int getButtonEventCount();
-  com.google.vr.vrcore.controller.api.ControllerButtonEvent getButtonEvent(int);
-  com.google.vr.vrcore.controller.api.ControllerEventPacket obtain();
-  com.google.vr.vrcore.controller.api.ControllerAccelEvent getAccelEvent(int);
-  void checkIsValidEventCount(int);
-  int getOrientationEventCount();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerEventPacket$1 {
-  com.google.vr.vrcore.controller.api.ControllerEventPacket[] newArray(int);
-   <init>();
-  com.google.vr.vrcore.controller.api.ControllerEventPacket createFromParcel(android.os.Parcel);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerEventPacket2 {
-  com.google.vr.vrcore.controller.api.ControllerEventPacket2 obtain();
-  void setControllerIndex(int, int, com.google.vr.vrcore.controller.api.ControllerEvent[]);
-   <init>();
-  void readFromParcel(android.os.Parcel);
-  int getPositionEventCount();
-  android.os.Parcelable$Creator CREATOR;
-  java.lang.Object poolLock;
-  com.google.vr.vrcore.controller.api.ControllerPositionEvent getPositionEvent(int);
-  boolean hasBatteryEvent;
-  long getSystemTimeMillis();
-  boolean hasBatteryEvent();
-  com.google.vr.vrcore.controller.api.ControllerPositionEvent[] positionEvents;
-  int positionEventCount;
-  void recycle();
-  int calculateParcelByteLength();
-  void setEventsControllerIndex(int);
-  com.google.vr.vrcore.controller.api.ControllerBatteryEvent batteryEvent;
-  void checkIsValidEventCount(int);
-  java.util.ArrayDeque pool;
-  long timestampMillis;
-  long getTimestampMillis();
-  com.google.vr.vrcore.controller.api.ControllerBatteryEvent getBatteryEvent();
-  void clear();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerEventPacket2$1 {
-  com.google.vr.vrcore.controller.api.ControllerEventPacket2 createFromParcel(android.os.Parcel);
-  com.google.vr.vrcore.controller.api.ControllerEventPacket2[] newArray(int);
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerGyroEvent {
-  void readFromParcel(android.os.Parcel);
-  int getByteSize();
-  long timestampNanos;
-  void writeToParcel(android.os.Parcel, int);
-  void copyFrom(com.google.vr.vrcore.controller.api.ControllerEvent);
-  float x;
-  int controllerId;
-  float y;
-   <init>();
-  float z;
-   <init>(android.os.Parcel);
-  android.os.Parcelable$Creator CREATOR;
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerGyroEvent$1 {
-   <init>();
-  com.google.vr.vrcore.controller.api.ControllerGyroEvent createFromParcel(android.os.Parcel);
-  com.google.vr.vrcore.controller.api.ControllerGyroEvent[] newArray(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerInitResults {
-  java.lang.String toString(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerListenerOptions {
-  boolean enableGestures;
-  boolean enableOrientation;
-   <init>(android.os.Parcel);
-  boolean enableAccel;
-  android.os.Parcelable$Creator CREATOR;
-   <init>(int);
-  boolean enableGyro;
-   <init>();
-  boolean enableTouch;
-  void readFromParcel(android.os.Parcel);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerListenerOptions$1 {
-  com.google.vr.vrcore.controller.api.ControllerListenerOptions createFromParcel(android.os.Parcel);
-   <init>();
-  com.google.vr.vrcore.controller.api.ControllerListenerOptions[] newArray(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerOrientationEvent {
-  int getByteSize();
-  void readFromParcel(android.os.Parcel);
-   <init>(android.os.Parcel);
-  float qy;
-  float qx;
-  float qw;
-  android.os.Parcelable$Creator CREATOR;
-  void copyFrom(com.google.vr.vrcore.controller.api.ControllerEvent);
-  int controllerId;
-  void writeToParcel(android.os.Parcel, int);
-  long timestampNanos;
-  float qz;
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerOrientationEvent$1 {
-  com.google.vr.vrcore.controller.api.ControllerOrientationEvent[] newArray(int);
-  com.google.vr.vrcore.controller.api.ControllerOrientationEvent createFromParcel(android.os.Parcel);
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerPositionEvent {
-  void copyFrom(com.google.vr.vrcore.controller.api.ControllerEvent);
-   <init>(android.os.Parcel);
-  float x;
-  int controllerId;
-  void readFromParcel(android.os.Parcel);
-  void writeToParcel(android.os.Parcel, int);
-  long timestampNanos;
-  android.os.Parcelable$Creator CREATOR;
-   <init>();
-  float z;
-  float y;
-  int getByteSize();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerPositionEvent$1 {
-  com.google.vr.vrcore.controller.api.ControllerPositionEvent[] newArray(int);
-   <init>();
-  com.google.vr.vrcore.controller.api.ControllerPositionEvent createFromParcel(android.os.Parcel);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerRequest {
-   <init>();
-   <init>(android.os.Parcel);
-  void setFromProto(com.google.protobuf.nano.MessageNano);
-  android.os.Parcelable$Creator CREATOR;
-  com.google.protobuf.nano.MessageNano parseToProto(java.lang.Class);
-  void checkArgument(boolean, java.lang.String, java.lang.Object[]);
-  byte[] getData();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerRequest$1 {
-  com.google.vr.vrcore.controller.api.ControllerRequest[] newArray(int);
-   <init>();
-  com.google.vr.vrcore.controller.api.ControllerRequest createFromParcel(android.os.Parcel);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerTouchEvent {
-  android.os.Parcelable$Creator CREATOR;
-  int action;
-  float x;
-  float y;
-  int getByteSize();
-  int fingerId;
-  void copyFrom(com.google.vr.vrcore.controller.api.ControllerEvent);
-  int controllerId;
-   <init>();
-  long timestampNanos;
-  void readFromParcel(android.os.Parcel);
-  void writeToParcel(android.os.Parcel, int);
-   <init>(android.os.Parcel);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.ControllerTouchEvent$1 {
-   <init>();
-  com.google.vr.vrcore.controller.api.ControllerTouchEvent createFromParcel(android.os.Parcel);
-  com.google.vr.vrcore.controller.api.ControllerTouchEvent[] newArray(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerListener$Stub {
-  int getApiVersion();
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-  void onControllerEventPacket(com.google.vr.vrcore.controller.api.ControllerEventPacket);
-  void attachInterface(android.os.IInterface, java.lang.String);
-  void onControllerRecentered(com.google.vr.vrcore.controller.api.ControllerOrientationEvent);
-  com.google.vr.vrcore.controller.api.ControllerListenerOptions getOptions();
-  void onControllerStateChanged(int, int);
-  void onControllerEventPacket2(com.google.vr.vrcore.controller.api.ControllerEventPacket2);
-  com.google.vr.vrcore.controller.api.IControllerListener asInterface(android.os.IBinder);
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerListener$Stub$Proxy {
-   <init>(android.os.IBinder);
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-  void transactOneway(int, android.os.Parcel);
-  android.os.Parcel obtainAndWriteInterfaceToken();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerService {
-  boolean unregisterServiceListener(com.google.vr.vrcore.controller.api.IControllerServiceListener);
-  boolean registerServiceListener(com.google.vr.vrcore.controller.api.IControllerServiceListener);
-  void request(int, com.google.vr.vrcore.controller.api.ControllerRequest);
-  int initialize(int);
-  int getNumberOfControllers();
-  boolean registerListener(int, java.lang.String, com.google.vr.vrcore.controller.api.IControllerListener);
-  boolean unregisterListener(java.lang.String);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerService$Stub {
-  int getNumberOfControllers();
-  void onHeadTrackingRecentered(float[], float[]);
-  int initialize(int);
-  boolean registerListener(int, java.lang.String, com.google.vr.vrcore.controller.api.IControllerListener);
-  boolean unregisterListener(java.lang.String);
-  com.google.vr.vrcore.controller.api.IControllerService asInterface(android.os.IBinder);
-  boolean unregisterServiceListener(com.google.vr.vrcore.controller.api.IControllerServiceListener);
-  void request(int, com.google.vr.vrcore.controller.api.ControllerRequest);
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-  boolean registerServiceListener(com.google.vr.vrcore.controller.api.IControllerServiceListener);
-  void attachInterface(android.os.IInterface, java.lang.String);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerService$Stub$Proxy {
-  android.os.Parcel obtainAndWriteInterfaceToken();
-  void transactAndReadExceptionReturnVoid(int, android.os.Parcel);
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-   <init>(android.os.IBinder);
-  void transactOneway(int, android.os.Parcel);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerServiceListener$Stub {
-   <init>();
-  void onControllerServiceEvent(int);
-  void attachInterface(android.os.IInterface, java.lang.String);
-  int getApiVersion();
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-  com.google.vr.vrcore.controller.api.IControllerServiceListener asInterface(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.IControllerServiceListener$Stub$Proxy {
-  android.os.Parcel obtainAndWriteInterfaceToken();
-   <init>(android.os.IBinder);
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-  void transactOneway(int, android.os.Parcel);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.nano.Proto$Request {
-  com.google.vr.vrcore.controller.api.nano.Proto$Request clear();
-  com.google.vr.vrcore.controller.api.nano.Proto$Request[] _emptyArray;
-   <init>();
-  com.google.vr.vrcore.controller.api.nano.Proto$Request clone();
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  com.google.vr.vrcore.controller.api.nano.Proto$Request mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-  com.google.vr.vrcore.controller.api.nano.Proto$Request$Vibration vibration;
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.controller.api.nano.Proto$Request$Vibration {
-  int cachedSize;
-  int volumePercentage_;
-  int getFrequencyHz();
-  com.google.vr.vrcore.controller.api.nano.Proto$Request$Vibration setDurationMs(int);
-  int frequencyHz_;
-  int bitField0_;
-  com.google.vr.vrcore.controller.api.nano.Proto$Request$Vibration clone();
-  com.google.vr.vrcore.controller.api.nano.Proto$Request$Vibration clear();
-   <init>();
-  com.google.vr.vrcore.controller.api.nano.Proto$Request$Vibration mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int durationMs_;
-  com.google.vr.vrcore.controller.api.nano.Proto$Request$Vibration setFrequencyHz(int);
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  int getVolumePercentage();
-  com.google.vr.vrcore.controller.api.nano.Proto$Request$Vibration[] _emptyArray;
-  int getDurationMs();
-  com.google.vr.vrcore.controller.api.nano.Proto$Request$Vibration setVolumePercentage(int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IGvrLayout {
-  boolean enableAsyncReprojection(int);
-  void onBackPressed();
-  void onPause();
-  void setStereoModeEnabled(boolean);
-  com.google.vr.vrcore.library.api.IObjectWrapper getRootView();
-  com.google.vr.vrcore.library.api.IGvrUiLayout getUiLayout();
-  long getNativeGvrContext();
-  void onResume();
-  boolean enableCardboardTriggerEmulation(com.google.vr.vrcore.library.api.IObjectWrapper);
-  boolean setOnDonNotNeededListener(com.google.vr.vrcore.library.api.IObjectWrapper);
-  void shutdown();
-  void setReentryIntent(com.google.vr.vrcore.library.api.IObjectWrapper);
-  void setPresentationView(com.google.vr.vrcore.library.api.IObjectWrapper);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IGvrLayout$Stub {
-  void onResume();
-  com.google.vr.vrcore.library.api.IObjectWrapper getRootView();
-  void attachInterface(android.os.IInterface, java.lang.String);
-  void setReentryIntent(com.google.vr.vrcore.library.api.IObjectWrapper);
-   <init>();
-  com.google.vr.vrcore.library.api.IGvrUiLayout getUiLayout();
-  boolean enableCardboardTriggerEmulation(com.google.vr.vrcore.library.api.IObjectWrapper);
-  boolean setOnDonNotNeededListener(com.google.vr.vrcore.library.api.IObjectWrapper);
-  void setPresentationView(com.google.vr.vrcore.library.api.IObjectWrapper);
-  com.google.vr.vrcore.library.api.IGvrLayout asInterface(android.os.IBinder);
-  void onPause();
-  long getNativeGvrContext();
-  void shutdown();
-  boolean enableAsyncReprojection(int);
-  void setStereoModeEnabled(boolean);
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-  void onBackPressed();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IGvrLayout$Stub$Proxy {
-  android.os.Parcel obtainAndWriteInterfaceToken();
-  void transactAndReadExceptionReturnVoid(int, android.os.Parcel);
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-   <init>(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IGvrUiLayout {
-  void setEnabled(boolean);
-  void setSettingsButtonListener(com.google.vr.vrcore.library.api.IObjectWrapper);
-  void setTransitionViewEnabled(boolean);
-  void setSettingsButtonEnabled(boolean);
-  void setViewerName(java.lang.String);
-  void setTransitionViewListener(com.google.vr.vrcore.library.api.IObjectWrapper);
-  void setCloseButtonListener(com.google.vr.vrcore.library.api.IObjectWrapper);
-  boolean isEnabled();
-  com.google.vr.vrcore.library.api.IObjectWrapper getRootView();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IGvrUiLayout$Stub {
-  void setTransitionViewListener(com.google.vr.vrcore.library.api.IObjectWrapper);
-  com.google.vr.vrcore.library.api.IGvrUiLayout asInterface(android.os.IBinder);
-  com.google.vr.vrcore.library.api.IObjectWrapper getRootView();
-  void setSettingsButtonEnabled(boolean);
-  void setSettingsButtonListener(com.google.vr.vrcore.library.api.IObjectWrapper);
-  void attachInterface(android.os.IInterface, java.lang.String);
-  void setEnabled(boolean);
-  void setCloseButtonListener(com.google.vr.vrcore.library.api.IObjectWrapper);
-  boolean isEnabled();
-  void setTransitionViewEnabled(boolean);
-   <init>();
-  void setViewerName(java.lang.String);
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IGvrUiLayout$Stub$Proxy {
-  void transactAndReadExceptionReturnVoid(int, android.os.Parcel);
-  android.os.Parcel obtainAndWriteInterfaceToken();
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-   <init>(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IObjectWrapper {
-  android.os.IBinder asBinder();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IObjectWrapper$Stub {
-  void attachInterface(android.os.IInterface, java.lang.String);
-   <init>();
-  com.google.vr.vrcore.library.api.IObjectWrapper asInterface(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IObjectWrapper$Stub$Proxy {
-   <init>(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IVrCreator {
-  com.google.vr.vrcore.library.api.IVrNativeLibraryLoader newNativeLibraryLoader(com.google.vr.vrcore.library.api.IObjectWrapper, com.google.vr.vrcore.library.api.IObjectWrapper);
-  com.google.vr.vrcore.library.api.IGvrLayout newGvrLayout(com.google.vr.vrcore.library.api.IObjectWrapper, com.google.vr.vrcore.library.api.IObjectWrapper);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IVrCreator$Stub {
-  com.google.vr.vrcore.library.api.IVrCreator asInterface(android.os.IBinder);
-  com.google.vr.vrcore.library.api.IVrNativeLibraryLoader DEPRECATED_newNativeLibraryLoader(com.google.vr.vrcore.library.api.IObjectWrapper);
-  com.google.vr.vrcore.library.api.IGvrLayout newGvrLayout(com.google.vr.vrcore.library.api.IObjectWrapper, com.google.vr.vrcore.library.api.IObjectWrapper);
-  void attachInterface(android.os.IInterface, java.lang.String);
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-  com.google.vr.vrcore.library.api.IVrNativeLibraryLoader newNativeLibraryLoader(com.google.vr.vrcore.library.api.IObjectWrapper, com.google.vr.vrcore.library.api.IObjectWrapper);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IVrCreator$Stub$Proxy {
-   <init>(android.os.IBinder);
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-  android.os.Parcel obtainAndWriteInterfaceToken();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IVrNativeLibraryLoader {
-  long loadNativeGvrLibrary(int, int, int);
-  long loadNativeGvrLibraryWithMinVersion(java.lang.String, java.lang.String);
-  long loadNativeDlsymMethod();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IVrNativeLibraryLoader$Stub {
-  void closeNativeGvrLibrary(long);
-  long loadNativeGvrLibraryWithMinVersion(java.lang.String, java.lang.String);
-  long loadNativeDlsymMethod();
-  com.google.vr.vrcore.library.api.IVrNativeLibraryLoader asInterface(android.os.IBinder);
-  long loadNativeGvrLibrary(int, int, int);
-  void attachInterface(android.os.IInterface, java.lang.String);
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.IVrNativeLibraryLoader$Stub$Proxy {
-  android.os.Parcel obtainAndWriteInterfaceToken();
-  void transactAndReadExceptionReturnVoid(int, android.os.Parcel);
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-   <init>(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.ObjectWrapper {
-  java.lang.Object wrappedObject;
-  java.lang.Object unwrap(com.google.vr.vrcore.library.api.IObjectWrapper, java.lang.Class);
-   <init>(java.lang.Object);
-  com.google.vr.vrcore.library.api.IObjectWrapper wrap(java.lang.Object);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.library.api.VrCoreLoader {
-  java.lang.String TAG;
-  int getRemoteContextClientApiVersion(android.content.Context);
-  com.google.vr.vrcore.library.api.IVrCreator getRemoteCreator(android.content.Context);
-  com.google.vr.vrcore.library.api.IVrCreator sCreator;
-  int sRemoteContextApiVersion;
-  android.content.Context sRemoteContext;
-  android.content.Context getRemoteContext(android.content.Context);
-  android.os.IBinder newBinderInstance(java.lang.ClassLoader, java.lang.String);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.logging.api.IVrCoreLoggingService {
-  void log(com.google.vr.vrcore.logging.api.VREventParcelable);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.logging.api.IVrCoreLoggingService$Stub {
-  void logBatched(com.google.vr.vrcore.logging.api.VREventParcelable[]);
-  void attachInterface(android.os.IInterface, java.lang.String);
-  com.google.vr.vrcore.logging.api.IVrCoreLoggingService asInterface(android.os.IBinder);
-  void log(com.google.vr.vrcore.logging.api.VREventParcelable);
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.logging.api.IVrCoreLoggingService$Stub$Proxy {
-  void transactOneway(int, android.os.Parcel);
-  android.os.Parcel obtainAndWriteInterfaceToken();
-   <init>(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.logging.api.VREventParcelable {
-   <init>(int, com.google.common.logging.nano.Vr$VREvent);
-  com.google.common.logging.nano.Vr$VREvent event;
-  int eventCode;
-   <init>(android.os.Parcel);
-  java.lang.String TAG;
-  android.os.Parcelable$Creator CREATOR;
-   <init>(android.os.Parcel, com.google.vr.vrcore.logging.api.VREventParcelable$1);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.logging.api.VREventParcelable$1 {
-  com.google.vr.vrcore.logging.api.VREventParcelable[] newArray(int);
-  com.google.vr.vrcore.logging.api.VREventParcelable createFromParcel(android.os.Parcel);
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.performance.api.IPerformanceService {
-  void addTrigger(android.content.ComponentName, com.google.vr.vrcore.performance.api.IThrottlingTriggerCallback, long, float, int);
-  long getCurrentEstimatedThrottleWarningTime();
-  void getCurrentThrottlingRelativeTemperature(com.google.vr.vrcore.performance.api.TimestampedTemperature);
-  void removeAllTriggers(android.content.ComponentName);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.performance.api.IPerformanceService$Stub {
-  void getCurrentThrottlingRelativeTemperature(com.google.vr.vrcore.performance.api.TimestampedTemperature);
-  com.google.vr.vrcore.performance.api.IPerformanceService asInterface(android.os.IBinder);
-  void addTrigger(android.content.ComponentName, com.google.vr.vrcore.performance.api.IThrottlingTriggerCallback, long, float, int);
-  long getCurrentEstimatedThrottleWarningTime();
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-  void removeAllTriggers(android.content.ComponentName);
-  void attachInterface(android.os.IInterface, java.lang.String);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.performance.api.IPerformanceService$Stub$Proxy {
-  void transactAndReadExceptionReturnVoid(int, android.os.Parcel);
-   <init>(android.os.IBinder);
-  android.os.Parcel obtainAndWriteInterfaceToken();
-  android.os.Parcel transactAndReadException(int, android.os.Parcel);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.performance.api.IThrottlingTriggerCallback$Stub {
-  void onTriggerActivated(float, long);
-   <init>();
-  com.google.vr.vrcore.performance.api.IThrottlingTriggerCallback asInterface(android.os.IBinder);
-  boolean routeToSuperOrEnforceInterface(int, android.os.Parcel, android.os.Parcel, int);
-  void attachInterface(android.os.IInterface, java.lang.String);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.performance.api.IThrottlingTriggerCallback$Stub$Proxy {
-  void transactOneway(int, android.os.Parcel);
-  android.os.Parcel obtainAndWriteInterfaceToken();
-   <init>(android.os.IBinder);
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.performance.api.TimestampedTemperature {
-   <init>();
-  float temperature;
-  void set(long, float);
-  void readFromParcel(android.os.Parcel);
-  long timestamp;
-   <init>(android.os.Parcel);
-  android.os.Parcelable$Creator CREATOR;
-}
-
--keep,allowobfuscation class com.google.vr.vrcore.performance.api.TimestampedTemperature$1 {
-  com.google.vr.vrcore.performance.api.TimestampedTemperature createFromParcel(android.os.Parcel);
-  com.google.vr.vrcore.performance.api.TimestampedTemperature[] newArray(int);
-   <init>();
-}
-
--keep,allowobfuscation class com.google.vrtoolkit.cardboard.ScreenOnFlagHelper {
-  android.hardware.Sensor sensor;
-  boolean screenAlwaysOn;
-  android.hardware.SensorManager sensorManager;
-  android.app.Activity activity;
-  com.google.vrtoolkit.cardboard.SensorReadingStats sensorStats;
-  long lastSampleTimestamp;
-  void setKeepScreenOnFlag(boolean);
-  void updateFlag();
-  boolean isFlagSet;
-}
-
--keep,allowobfuscation class com.google.vrtoolkit.cardboard.SensorReadingStats {
-  void reset();
-  boolean statsAvailable();
-  int writePos;
-  float[][] sampleBuf;
-  int numAxes;
-  int samplesAdded;
-   <init>(int, int);
-  void addSample(float[]);
-  float getMaxAbsoluteDeviation();
-  int sampleBufSize;
-  float getAverage(int);
-  java.lang.String TAG;
-  float getMaxAbsoluteDeviation(int);
-}
-
--keep,allowobfuscation class logs.proto.wireless.performance.mobile.nano.MemoryMetric$AndroidMemoryStats {
-  java.lang.Integer nativePssKb;
-   <init>();
-  java.lang.Integer dalvikPssKb;
-  java.lang.Integer totalSwappablePssKb;
-  java.lang.Integer summaryCodeKb;
-  java.lang.Integer totalMemoryMb;
-  java.lang.Integer summarySystemKb;
-  com.google.protobuf.nano.FieldArray unknownFieldData;
-  java.lang.Integer otherGraphicsPssKb;
-  java.lang.Integer availableMemoryKb;
-  java.lang.Integer nativePrivateDirtyKb;
-  java.lang.Integer summaryPrivateOtherKb;
-  java.lang.Integer summaryStackKb;
-  java.lang.Integer totalPrivateCleanKb;
-  java.lang.Integer totalSharedDirtyKb;
-  logs.proto.wireless.performance.mobile.nano.MemoryMetric$AndroidMemoryStats clear();
-  logs.proto.wireless.performance.mobile.nano.MemoryMetric$AndroidMemoryStats clone();
-  logs.proto.wireless.performance.mobile.nano.MemoryMetric$AndroidMemoryStats mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano);
-  int cachedSize;
-  java.lang.Integer otherPssKb;
-  java.lang.Integer summaryGraphicsKb;
-  java.lang.Integer dalvikPrivateDirtyKb;
-  java.lang.Integer summaryJavaHeapKb;
-  java.lang.Integer otherPrivateDirtyKb;
-}
-
--keep,allowobfuscation class org.apache.http.conn.ssl.AbstractVerifier {
-   <init>();
-}
-
--keep,allowobfuscation class org.apache.http.conn.ssl.SSLSocketFactory {
-  org.apache.http.conn.ssl.X509HostnameVerifier STRICT_HOSTNAME_VERIFIER;
-  org.apache.http.conn.ssl.X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
-  org.apache.http.conn.ssl.X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER;
-}
-
--keep,allowobfuscation class org.chromium.base.ApiCompatibilityUtils {
-  int checkPermission(android.content.Context, java.lang.String, int, int);
-}
-
--keep,allowobfuscation class org.chromium.base.ApplicationStatus {
-  android.app.Activity getLastTrackedFocusedActivity();
-  void registerStateListenerForAllActivities(org.chromium.base.ApplicationStatus$ActivityStateListener);
-  int getStateForActivity(android.app.Activity);
-  void registerStateListenerForActivity(org.chromium.base.ApplicationStatus$ActivityStateListener, android.app.Activity);
-}
-
--keep,allowobfuscation class org.chromium.base.ContextUtils {
-  android.content.Context getApplicationContext();
-  android.content.SharedPreferences getAppSharedPreferences();
-}
-
--keep,allowobfuscation class org.chromium.base.Log {
-  void i(java.lang.String, java.lang.String, java.lang.Object[]);
-  void e(java.lang.String, java.lang.String, java.lang.Object[]);
-}
-
--keep,allowobfuscation class org.chromium.base.PackageUtils {
-  int getPackageVersion(android.content.Context, java.lang.String);
-}
-
--keep,allowobfuscation class org.chromium.base.StrictModeContext {
-  void close();
-  org.chromium.base.StrictModeContext allowDiskWrites();
-}
-
--keep,allowobfuscation class org.chromium.base.ThreadUtils {
-  void assertOnUiThread();
-}
-
--keep,allowobfuscation class org.chromium.base.TraceEvent {
-  void close();
-  org.chromium.base.TraceEvent scoped(java.lang.String);
-}
-
--keep,allowobfuscation class org.chromium.base.library_loader.LibraryLoader {
-  boolean isInitialized();
-  org.chromium.base.library_loader.LibraryLoader getInstance();
-}
-
--keep,allowobfuscation class org.chromium.base.metrics.CachedMetrics$BooleanHistogramSample {
-  void record(boolean);
-   <init>(java.lang.String);
-}
-
--keep,allowobfuscation class org.chromium.base.metrics.RecordUserAction {
-  void record(java.lang.String);
-}
-
--keep,allowobfuscation class org.chromium.base.task.AsyncTask {
-  java.util.concurrent.Executor THREAD_POOL_EXECUTOR;
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.base.task.PostTask {
-  java.lang.Object runSynchronously(org.chromium.base.task.TaskTraits, java.util.concurrent.Callable);
-  void runSynchronously(org.chromium.base.task.TaskTraits, java.lang.Runnable);
-  void postTask(org.chromium.base.task.TaskTraits, java.lang.Runnable);
-}
-
--keep,allowobfuscation class org.chromium.build.BuildHooksAndroid {
-  boolean isEnabledImpl();
-  void initCustomResourcesImpl(android.content.Context);
-  android.content.Context createConfigurationContextImpl(android.content.Context);
-  void maybeRecordResourceMetricsImpl();
-  android.content.res.Resources getResourcesImpl(android.content.Context);
-  org.chromium.build.BuildHooksAndroid get();
-  android.content.res.Resources$Theme getThemeImpl(android.content.Context);
-  int getIdentifierImpl(android.content.res.Resources, java.lang.String, java.lang.String, java.lang.String);
-  org.chromium.build.BuildHooksAndroid sInstance;
-  android.content.res.AssetManager getAssetsImpl(android.content.Context);
-  org.chromium.build.BuildHooksAndroid constructBuildHooksAndroidImpl();
-  void setThemeImpl(android.content.Context, int);
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.chrome.R$anim {
-  int stay_hidden;
-}
-
--keep,allowobfuscation class org.chromium.chrome.R$id {
-  int new_tab_button;
-  int recent_tabs_menu_id;
-  int vr_overlay_view;
-  int help_id;
-  int open_history_menu_id;
-  int share_menu_id;
-  int downloads_menu_id;
-  int all_bookmarks_menu_id;
-  int preferences_id;
-}
-
--keep,allowobfuscation class org.chromium.chrome.R$layout {
-  int modal_dialog_view;
-}
-
--keep,allowobfuscation class org.chromium.chrome.R$string {
-  int no_thanks;
-}
-
--keep,allowobfuscation class org.chromium.chrome.R$style {
-  int Theme_Chromium_ModalDialog;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.ApplicationLifetime {
-  void terminate(boolean);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.ChromeActivity {
-  boolean onMenuOrKeyboardAction(int, boolean);
-  org.chromium.chrome.browser.toolbar.ToolbarManager getToolbarManager();
-  boolean isInOverviewMode();
-  void onExitVr();
-  boolean hasWindowFocus();
-  void recreate();
-  org.chromium.chrome.browser.tabmodel.TabCreatorManager$TabCreator getTabCreator(boolean);
-  boolean isActivityFinishingOrDestroyed();
-  void unregisterReceiver(android.content.BroadcastReceiver);
-  android.content.res.Resources getResources();
-  void overrideModalDialogManager(org.chromium.ui.modaldialog.ModalDialogManager);
-  int getRequestedOrientation();
-  org.chromium.ui.modaldialog.ModalDialogManager getModalDialogManager();
-  int getTaskId();
-  void setRequestedOrientation(int);
-  android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
-  boolean isFinishing();
-  org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager getFullscreenManager();
-  org.chromium.chrome.browser.tabmodel.TabModelSelector getTabModelSelector();
-  org.chromium.chrome.browser.widget.findinpage.FindToolbarManager getFindToolbarManager();
-  org.chromium.chrome.browser.tab.Tab getActivityTab();
-  android.view.View findViewById(int);
-  void startActivity(android.content.Intent, android.os.Bundle);
-  android.view.WindowManager getWindowManager();
-  java.lang.String getPackageName();
-  android.content.ContentResolver getContentResolver();
-  org.chromium.chrome.browser.tabmodel.TabCreatorManager$TabCreator getCurrentTabCreator();
-  android.view.Window getWindow();
-  org.chromium.ui.base.ActivityWindowAndroid getWindowAndroid();
-  void startActivityForResult(android.content.Intent, int);
-  void onEnterVr();
-  java.lang.String getString(int);
-  org.chromium.chrome.browser.compositor.CompositorViewHolder getCompositorViewHolder();
-  android.content.Intent getIntent();
-  android.content.Context getApplicationContext();
-  java.lang.Object getSystemService(java.lang.String);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.ChromeFeatureList {
-  int getFieldTrialParamByFeatureAsInt(java.lang.String, java.lang.String, int);
-  boolean isEnabled(java.lang.String);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.ChromeTabbedActivity {
-  boolean handleBackPressed();
-  boolean backShouldCloseTab(org.chromium.chrome.browser.tab.Tab);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.compositor.CompositorSurfaceManager$SurfaceManagerCallbackTarget {
-  void surfaceDestroyed(android.view.Surface);
-  void surfaceChanged(android.view.Surface, int, int, int);
-  void surfaceCreated(android.view.Surface);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.compositor.CompositorView {
-  void replaceSurfaceManagerForVr(org.chromium.chrome.browser.compositor.CompositorSurfaceManager, org.chromium.ui.base.WindowAndroid);
-  void surfaceRedrawNeededAsync(java.lang.Runnable);
-  void onExitVr(org.chromium.ui.base.WindowAndroid);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.compositor.CompositorViewHolder {
-  org.chromium.chrome.browser.compositor.CompositorView getCompositorView();
-  void onEnterVr();
-  boolean requestFocus();
-  void onExitVr();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager {
-  int getContentOffset();
-  void exitPersistentFullscreenMode();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.help.HelpAndFeedback {
-  void showFeedback(android.app.Activity, org.chromium.chrome.browser.profiles.Profile, java.lang.String, java.lang.String);
-  org.chromium.chrome.browser.help.HelpAndFeedback getInstance(android.content.Context);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder {
-  void create(org.chromium.chrome.browser.tab.Tab, org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder$Listener, int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.modaldialog.ModalDialogViewBinder {
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.page_info.PageInfoController {
-  void show(android.app.Activity, org.chromium.chrome.browser.tab.Tab, java.lang.String, int);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.preferences.ChromePreferenceManager {
-  void writeBoolean(java.lang.String, boolean);
-  org.chromium.chrome.browser.preferences.ChromePreferenceManager getInstance();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tab.EmptyTabObserver {
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tab.Tab {
-  org.chromium.ui.base.WindowAndroid getWindowAndroid();
-  java.lang.String getTitle();
-  void removeObserver(org.chromium.chrome.browser.tab.TabObserver);
-  boolean isIncognito();
-  int getId();
-  android.view.ViewGroup getContentView();
-  org.chromium.chrome.browser.profiles.Profile getProfile();
-  boolean canGoForward();
-  org.chromium.content_public.browser.WebContents getWebContents();
-  void reload();
-  void addObserver(org.chromium.chrome.browser.tab.TabObserver);
-  boolean canGoBack();
-  java.lang.String getUrl();
-  org.chromium.chrome.browser.ChromeActivity getActivity();
-  void updateWindowAndroid(org.chromium.ui.base.WindowAndroid);
-  int loadUrl(org.chromium.content_public.browser.LoadUrlParams);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tab.TabAssociatedApp {
-  boolean isOpenedFromExternalApp(org.chromium.chrome.browser.tab.Tab);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tab.TabBrowserControlsState {
-  void update(org.chromium.chrome.browser.tab.Tab, int, boolean);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tab.TabObserver {
-  void onContentChanged(org.chromium.chrome.browser.tab.Tab);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tab.TabRedirectHandler {
-   <init>(android.content.Context);
-  org.chromium.chrome.browser.tab.TabRedirectHandler swapFor(org.chromium.chrome.browser.tab.Tab, org.chromium.chrome.browser.tab.TabRedirectHandler);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tabmodel.ChromeTabCreator {
-  void setWindowAndroid(org.chromium.ui.base.WindowAndroid);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver {
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tabmodel.TabCreatorManager$TabCreator {
-  org.chromium.chrome.browser.tab.Tab createNewTab(org.chromium.content_public.browser.LoadUrlParams, int, org.chromium.chrome.browser.tab.Tab);
-  void launchNTP();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tabmodel.TabModel {
-  org.chromium.chrome.browser.tab.Tab getTabAt(int);
-  void closeAllTabs();
-  int getCount();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tabmodel.TabModelSelector {
-  org.chromium.chrome.browser.tabmodel.TabModel getModel(boolean);
-  void removeObserver(org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver);
-  java.util.List getModels();
-  int getTotalTabCount();
-  void addObserver(org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver {
-  void destroy();
-   <init>(org.chromium.chrome.browser.tabmodel.TabModelSelector);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.toolbar.NewTabButton {
-  boolean callOnClick();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.toolbar.ToolbarManager {
-  boolean back();
-  boolean forward();
-  void setProgressBarEnabled(boolean);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.util.FeatureUtilities {
-  boolean isRecognitionIntentPresent(android.content.Context, boolean);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.util.IntentUtils {
-  android.os.Parcelable safeGetParcelableExtra(android.content.Intent, java.lang.String);
-  boolean safeStartActivity(android.content.Context, android.content.Intent);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.AndroidUiGestureTarget {
-  long access$002(org.chromium.chrome.browser.vr.AndroidUiGestureTarget, long);
-   <init>(android.view.View, float, float, int);
-  long mNativePointer;
-  org.chromium.content_public.browser.MotionEventSynthesizer mMotionEventSynthesizer;
-  long mLastTimestampMs;
-  long access$000(org.chromium.chrome.browser.vr.AndroidUiGestureTarget);
-  long nativeInit(float, float, int);
-  org.chromium.content_public.browser.MotionEventSynthesizer access$100(org.chromium.chrome.browser.vr.AndroidUiGestureTarget);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.AndroidUiGestureTarget$1 {
-  int val$x;
-  org.chromium.chrome.browser.vr.AndroidUiGestureTarget this$0;
-  int val$action;
-  long val$timeInMs;
-  int val$delayMs;
-  int val$y;
-   <init>(org.chromium.chrome.browser.vr.AndroidUiGestureTarget, long, int, int, int, int);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.AndroidVSyncHelper {
-   <init>(long);
-  android.view.Choreographer$FrameCallback mCallback;
-  long mNativeAndroidVSyncHelper;
-  long access$000(org.chromium.chrome.browser.vr.AndroidVSyncHelper);
-  void access$100(org.chromium.chrome.browser.vr.AndroidVSyncHelper, long, long);
-  void nativeOnVSync(long, long);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.AndroidVSyncHelper$1 {
-  org.chromium.chrome.browser.vr.AndroidVSyncHelper this$0;
-   <init>(org.chromium.chrome.browser.vr.AndroidVSyncHelper);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.EmptySniffingVrViewContainer {
-  android.view.View getChildAt(int);
-  java.lang.Boolean mEmpty;
-  void onEmpty();
-  org.chromium.chrome.browser.vr.NoopCanvas mNoopCanvas;
-  void resize(int, int);
-   <init>(android.content.Context, org.chromium.chrome.browser.vr.EmptySniffingVrViewContainer$EmptyListener);
-  void onNonEmpty();
-  int getChildCount();
-  void postInvalidate();
-  void removeAllViews();
-  void destroy();
-  org.chromium.chrome.browser.vr.EmptySniffingVrViewContainer$EmptyListener mListener;
-  android.view.ViewParent getParent();
-  android.view.View getInputTarget();
-  void addView(android.view.View);
-  void setSurface(android.view.Surface);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.EmptySniffingVrViewContainer$EmptyListener {
-  void onVrViewEmpty();
-  void onVrViewNonEmpty();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.NoopCanvas {
-  void restoreToCount(int);
-   <init>(android.graphics.Bitmap, boolean);
-  org.chromium.chrome.browser.vr.NoopCanvas$NoopException mException;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.NoopCanvas$1 {
-  org.chromium.chrome.browser.vr.NoopCanvas this$0;
-   <init>(org.chromium.chrome.browser.vr.NoopCanvas);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.NoopCanvas$NoopException {
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.OnDispatchTouchEventCallback {
-  void onDispatchTouchEvent(boolean);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.OnExitVrRequestListener {
-  void onDenied();
-  void onSucceeded();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrAlertDialog {
-  org.chromium.chrome.browser.vr.VrAlertDialog$DialogButton access$000(org.chromium.chrome.browser.vr.VrAlertDialog);
-  org.chromium.ui.modelutil.PropertyModel mModalDialogModel;
-  java.lang.CharSequence mMessage;
-  org.chromium.chrome.browser.vr.VrAlertDialog$DialogButton access$100(org.chromium.chrome.browser.vr.VrAlertDialog);
-  android.view.View mView;
-   <init>(android.content.Context, org.chromium.ui.modaldialog.ModalDialogManager);
-  org.chromium.chrome.browser.vr.VrAlertDialog$DialogButton mButtonPositive;
-  org.chromium.ui.modaldialog.ModalDialogManager mModalDialogManager;
-  org.chromium.chrome.browser.vr.VrAlertDialog$DialogButton mButtonNegative;
-  boolean $assertionsDisabled;
-  void dismiss();
-  org.chromium.ui.modelutil.PropertyModel createDialogModel();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrAlertDialog$1 {
-  org.chromium.chrome.browser.vr.VrAlertDialog this$0;
-   <init>(org.chromium.chrome.browser.vr.VrAlertDialog);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrAlertDialog$DialogButton {
-  int getId();
-  java.lang.String mText;
-  org.chromium.chrome.browser.vr.VrAlertDialog this$0;
-  java.lang.String getText();
-  android.content.DialogInterface$OnClickListener getListener();
-  android.content.DialogInterface$OnClickListener mListener;
-  int mId;
-   <init>(org.chromium.chrome.browser.vr.VrAlertDialog, int, java.lang.String, android.content.DialogInterface$OnClickListener);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrCancelAnimationActivity {
-  void overridePendingTransition(int, int);
-  void finish();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrCompositorSurfaceManager {
-  int mFormat;
-  void surfaceResized(int, int);
-  void setSurface(android.view.Surface, int, int, int);
-  void shutDown();
-   <init>(org.chromium.chrome.browser.compositor.CompositorSurfaceManager$SurfaceManagerCallbackTarget);
-  void surfaceDestroyed();
-  org.chromium.chrome.browser.compositor.CompositorSurfaceManager$SurfaceManagerCallbackTarget mClient;
-  int mHeight;
-  int mWidth;
-  android.view.Surface mSurface;
-  boolean $assertionsDisabled;
-  int mSurfaceState;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrCoreInfo {
-   <init>(org.chromium.chrome.browser.vr.VrCoreInfo$GvrVersion, int);
-  org.chromium.chrome.browser.vr.VrCoreInfo$GvrVersion gvrVersion;
-  int compatibility;
-  long nativeInit(int, int, int, int);
-  long makeNativeVrCoreInfo();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrCoreInfo$GvrVersion {
-   <init>(int, int, int);
-  int majorVersion;
-  int patchVersion;
-  int minorVersion;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrCoreVersionChecker {
-  int getVrCoreCompatibility();
-  long makeNativeVrCoreInfo();
-  org.chromium.chrome.browser.vr.VrCoreInfo getVrCoreInfo();
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrDaydreamApi {
-  boolean launchInVr(android.app.PendingIntent);
-  boolean registerDaydreamIntent(android.app.PendingIntent);
-  boolean unregisterDaydreamIntent();
-  boolean exitFromVr(android.app.Activity, int, android.content.Intent);
-  com.google.vr.ndk.base.DaydreamApi mDaydreamApi;
-  com.google.vr.ndk.base.DaydreamApi getDaydreamApi();
-  boolean isDaydreamCurrentViewer();
-  boolean launchVrHomescreen();
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrDelegate {
-   <init>();
-  boolean relaunchOnMainDisplayIfNecessary(android.app.Activity, android.content.Intent);
-  void removeBlackOverlayView(android.app.Activity, boolean);
-  boolean bootsToVr();
-  boolean willChangeDensityInVr(org.chromium.chrome.browser.ChromeActivity);
-  boolean activitySupportsVrBrowsing(android.app.Activity);
-  void addBlackOverlayViewForActivity(org.chromium.chrome.browser.ChromeActivity);
-  void setSystemUiVisibilityForVr(android.app.Activity);
-  boolean USE_HIDE_ANIMATION;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrDelegateImpl {
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrDelegateProviderImpl {
-  org.chromium.chrome.browser.vr.VrIntentDelegateImpl mIntentDelegate;
-  org.chromium.chrome.browser.vr.VrDelegateImpl mDelegate;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrDialog {
-  void setBackgroundColor(int);
-  org.chromium.chrome.browser.vr.VrDialogManager access$000(org.chromium.chrome.browser.vr.VrDialog);
-  void addView(android.view.View, android.view.ViewGroup$LayoutParams);
-   <init>(android.content.Context, org.chromium.chrome.browser.vr.VrDialogManager);
-  int getWidth();
-  void setLayoutParams(android.view.ViewGroup$LayoutParams);
-  void dismiss();
-  org.chromium.chrome.browser.vr.VrDialogManager mVrDialogManager;
-  void addOnLayoutChangeListener(android.view.View$OnLayoutChangeListener);
-  void initVrDialog();
-  void disableSoftKeyboard(android.view.ViewGroup);
-  int getHeight();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrDialog$1 {
-  org.chromium.chrome.browser.vr.VrDialog this$0;
-   <init>(org.chromium.chrome.browser.vr.VrDialog);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrDialogManager {
-  void setDialogView(android.view.View);
-  void setDialogFloating(boolean);
-  void setDialogSize(int, int);
-  void setDialogLocation(int, int);
-  void initVrDialog(int, int);
-  void closeVrDialog();
-  void setVrDialogDismissHandler(java.lang.Runnable);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrFeedbackStatus {
-  void setFeedbackOptOut(boolean);
-  boolean getFeedbackOptOut();
-  int getFeedbackFrequency();
-  void setUserExitedAndEntered2DCount(int);
-  int getUserExitedAndEntered2DCount();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrFirstRunActivity {
-  org.chromium.base.metrics.CachedMetrics$BooleanHistogramSample sFreNotCompleteBrowserHistogram;
-  void recordFreHistogram();
-  void showFre();
-  android.content.Intent getIntent();
-  void finish();
-  boolean $assertionsDisabled;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrFirstRunActivity$1 {
-   <init>(org.chromium.chrome.browser.vr.VrFirstRunActivity, org.chromium.chrome.browser.vr.VrDaydreamApi);
-  org.chromium.chrome.browser.vr.VrFirstRunActivity this$0;
-  org.chromium.chrome.browser.vr.VrDaydreamApi val$daydreamApi;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrInputConnection {
-  org.chromium.content_public.browser.ImeAdapter mImeAdapter;
-  void access$100(org.chromium.chrome.browser.vr.VrInputConnection, long, java.lang.String);
-  long mNativeVrInputConnection;
-   <init>(long, org.chromium.content_public.browser.WebContents);
-  android.os.Handler mImeThreadResponseHandler;
-  android.os.Handler access$200(org.chromium.chrome.browser.vr.VrInputConnection);
-  boolean $assertionsDisabled;
-  void nativeUpdateTextState(long, java.lang.String);
-  long access$000(org.chromium.chrome.browser.vr.VrInputConnection);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrInputConnection$1 {
-   <init>(org.chromium.chrome.browser.vr.VrInputConnection, android.view.inputmethod.InputConnection);
-  org.chromium.chrome.browser.vr.VrInputConnection this$0;
-  android.view.inputmethod.InputConnection val$ic;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrInputConnection$1$1 {
-   <init>(org.chromium.chrome.browser.vr.VrInputConnection$1, java.lang.String);
-  java.lang.String val$textState;
-  org.chromium.chrome.browser.vr.VrInputConnection$1 this$1;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrInputConnection$2 {
-  boolean $assertionsDisabled;
-   <init>(org.chromium.chrome.browser.vr.VrInputConnection, android.view.inputmethod.InputConnection, org.chromium.chrome.browser.vr.keyboard.TextEditAction[]);
-  org.chromium.chrome.browser.vr.keyboard.TextEditAction[] val$edits;
-  android.view.inputmethod.InputConnection val$ic;
-  org.chromium.chrome.browser.vr.VrInputConnection this$0;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrInputConnection$3 {
-   <init>(org.chromium.chrome.browser.vr.VrInputConnection, android.view.inputmethod.InputConnection);
-  org.chromium.chrome.browser.vr.VrInputConnection this$0;
-  android.view.inputmethod.InputConnection val$ic;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrIntentDelegate {
-   <init>();
-  boolean isLaunchingIntoVr(android.app.Activity, android.content.Intent);
-  boolean isVrIntent(android.content.Intent);
-  android.content.Intent setupVrIntent(android.content.Intent);
-  void removeVrExtras(android.content.Intent);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrIntentDelegateImpl {
-  boolean isVrIntent(android.content.Intent);
-   <init>();
-  boolean $assertionsDisabled;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrModalPresenter {
-  android.content.Context mContext;
-  org.chromium.chrome.browser.vr.VrDialog mVrDialog;
-  void dismissCurrentDialog(int);
-  org.chromium.ui.modelutil.PropertyModelChangeProcessor mModelChangeProcessor;
-  void closeCurrentDialog();
-   <init>(android.content.Context, org.chromium.chrome.browser.vr.VrDialogManager);
-  org.chromium.chrome.browser.vr.VrDialogManager mVrDialogManager;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrModuleProvider {
-  void onExitVr();
-  org.chromium.chrome.browser.vr.VrDelegate getDelegate();
-  org.chromium.chrome.browser.vr.VrIntentDelegate getIntentDelegate();
-  void registerJni();
-  void onEnterVr();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrPopupWindow {
-  int mHeight;
-  android.graphics.drawable.Drawable getBackground();
-  void dismiss();
-  android.widget.PopupWindow$OnDismissListener mOnDismissListener;
-  android.content.Context mContext;
-  void showAtLocation(android.view.View, int, int, int);
-  android.view.View getContentView();
-  android.widget.FrameLayout mVrPopupContainer;
-   <init>(android.content.Context, org.chromium.chrome.browser.vr.VrDialogManager);
-  int mWidth;
-  boolean isShowing();
-  boolean mIsShowing;
-  org.chromium.chrome.browser.vr.VrDialogManager mVrDialogManager;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrPopupWindow$1 {
-   <init>(org.chromium.chrome.browser.vr.VrPopupWindow);
-  org.chromium.chrome.browser.vr.VrPopupWindow this$0;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell {
-  void nativeOnTriggerEvent(long, boolean);
-  org.chromium.chrome.browser.vr.VrShellDelegate access$1400(org.chromium.chrome.browser.vr.VrShell);
-  void onPause();
-  void restoreTabFromVR();
-  boolean mReprojectedRendering;
-  void nativeSetDialogLocation(long, float, float);
-  void nativeWatchElementForVisibilityStatusForTesting(long, int, int, boolean);
-  void nativeOnTabListCreated(long, org.chromium.chrome.browser.tab.Tab[], org.chromium.chrome.browser.tab.Tab[]);
-  void attachTabModelSelectorTabObserver();
-  void nativeOnTabUpdated(long, boolean, int, java.lang.String);
-   <init>(org.chromium.chrome.browser.ChromeActivity, org.chromium.chrome.browser.vr.VrShellDelegate, org.chromium.chrome.browser.tabmodel.TabModelSelector);
-  void setWebVrModeEnabled(boolean);
-  void nativeOnResume(long);
-  void setContentCssSize(float, float, float);
-  void swapToForegroundTab();
-  org.chromium.ui.modaldialog.ModalDialogManager mNonVrModalDialogManager;
-  void configWebContentsImeForVr(org.chromium.content_public.browser.WebContents);
-  void nativeDestroy(long);
-  void nativeSetUiExpectingActivityForTesting(long, int);
-  void requestToExitVr(int, boolean);
-  org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver mTabModelSelectorTabObserver;
-  void nativeAcceptDoffPromptForTesting(long);
-  org.chromium.chrome.browser.vr.EmptySniffingVrViewContainer mNonVrViews;
-  boolean nativeGetWebVrMode(long);
-  float mLastContentHeight;
-  void access$900(org.chromium.chrome.browser.vr.VrShell);
-  void nativeSetAlertDialogSize(long, float, float);
-  void restoreWebContentsImeFromVr(org.chromium.content_public.browser.WebContents);
-  org.chromium.chrome.browser.vr.VrModalPresenter mVrModalPresenter;
-  void launchNTP();
-  long access$100(org.chromium.chrome.browser.vr.VrShell);
-  void nativeSwapContents(long, org.chromium.chrome.browser.tab.Tab);
-  void nativeSetSurface(long, android.view.Surface);
-  int getTouchSlop();
-  org.chromium.chrome.browser.vr.VrWindowAndroid mContentVrWindowAndroid;
-  void nativeCancelToast(long);
-  void lambda$setWebVrModeEnabled$0();
-  void injectVrHostedUiView();
-  java.lang.Runnable mVrDialogDismissHandler;
-  void nativeSaveNextFrameBufferToDiskForTesting(long, java.lang.String);
-  org.chromium.chrome.browser.vr.VrViewContainer mVrUiViewContainer;
-  void nativeSetWebVrMode(long, boolean);
-  float mLastContentDpr;
-  void access$1000(org.chromium.chrome.browser.vr.VrShell, long, boolean, int, java.lang.String);
-  void nativeBufferBoundsChanged(long, int, int, int, int);
-  org.chromium.content_public.browser.ViewEventSink access$000(org.chromium.chrome.browser.vr.VrShell);
-  void access$700(org.chromium.chrome.browser.vr.VrShell, org.chromium.content_public.browser.WebContents);
-  void swapToTab(org.chromium.chrome.browser.tab.Tab);
-  void shutdown();
-  boolean $assertionsDisabled;
-  void pause();
-  void nativeSetAndroidGestureTarget(long, org.chromium.chrome.browser.vr.AndroidUiGestureTarget);
-  void setVisibility(int);
-  float access$300(org.chromium.chrome.browser.vr.VrShell);
-  java.lang.Boolean lambda$isDisplayingUrlForTesting$1();
-  android.view.View$OnTouchListener mTouchListener;
-  void nativeOnLoadProgressChanged(long, double);
-  void access$1500(org.chromium.chrome.browser.vr.VrShell, long, boolean, int);
-  org.chromium.chrome.browser.vr.VrCompositorSurfaceManager mVrCompositorSurfaceManager;
-  void nativeUpdateWebInputIndices(long, int, int, int, int);
-  boolean getWebVrModeEnabled();
-  java.util.ArrayList mUiOperationResultCallbacks;
-  android.view.Surface mContentSurface;
-  void nativeCloseAlertDialog(long);
-  long nativeInit(org.chromium.chrome.browser.vr.VrShellDelegate, boolean, boolean, boolean, long, boolean, float, float, int, int, boolean, boolean, boolean);
-  boolean nativeHasUiFinishedLoading(long);
-  void nativeSetAlertDialog(long, float, float);
-  org.chromium.chrome.browser.vr.AndroidUiGestureTarget mAndroidDialogGestureTarget;
-  boolean mPendingVSyncPause;
-  void nativeOnTabRemoved(long, boolean, int);
-  java.lang.Boolean mPaused;
-  org.chromium.chrome.browser.tab.TabRedirectHandler mNonVrTabRedirectHandler;
-  void access$1100(org.chromium.chrome.browser.vr.VrShell, long, boolean);
-  org.chromium.chrome.browser.vr.OnDispatchTouchEventCallback mOnDispatchTouchEventForTesting;
-  void nativeSetHistoryButtonsEnabled(long, boolean, boolean);
-  org.chromium.chrome.browser.compositor.CompositorView mCompositorView;
-  java.lang.Runnable mOnVSyncPausedForTesting;
-  org.chromium.chrome.browser.vr.AndroidUiGestureTarget mAndroidUiGestureTarget;
-  android.view.View mPresentationView;
-  void access$1200(org.chromium.chrome.browser.vr.VrShell, long, boolean);
-  void access$800(org.chromium.chrome.browser.vr.VrShell, long, double);
-  void teardown();
-  java.util.ArrayList mUiOperationResults;
-  org.chromium.chrome.browser.tab.TabObserver mTabObserver;
-  float getNativePageScrollRatio();
-  void lambda$rawTopContentOffsetChanged$2();
-  void nativeShowToast(long, java.lang.String);
-  org.chromium.chrome.browser.vr.VrInputConnection nativeGetVrInputConnectionForTesting(long);
-  float access$200(org.chromium.chrome.browser.vr.VrShell);
-  java.lang.Boolean mCanGoBack;
-  org.chromium.chrome.browser.tabmodel.TabModelSelector mTabModelSelector;
-  void nativeRequestToExitVr(long, int);
-  void createTabList();
-  void resume();
-  void setReentryIntent(android.app.PendingIntent);
-  void nativeRequestRecordAudioPermissionResult(long, boolean);
-  org.chromium.chrome.browser.tab.TabRedirectHandler mTabRedirectHandler;
-  void lambda$performKeyboardInputForTesting$3(int, java.lang.String);
-  org.chromium.content_public.browser.ViewEventSink mViewEventSink;
-  org.chromium.ui.modaldialog.ModalDialogManager mVrModalDialogManager;
-  void initializeNative(boolean, boolean);
-  void nativeOnPause(long);
-  void onResume();
-  org.chromium.ui.widget.UiWidgetFactory mNonVrUiWidgetFactory;
-  void openNewTab(boolean);
-  org.chromium.content_public.browser.ViewEventSink access$002(org.chromium.chrome.browser.vr.VrShell, org.chromium.content_public.browser.ViewEventSink);
-  org.chromium.chrome.browser.ChromeActivity mActivity;
-  void nativeSetDialogGestureTarget(long, org.chromium.chrome.browser.vr.AndroidUiGestureTarget);
-  org.chromium.ui.display.VirtualDisplayAndroid mContentVirtualDisplay;
-  boolean hasRecordAudioPermission();
-  void nativeLogUnsupportedModeUserMetric(long, int);
-  android.widget.FrameLayout getContainer();
-  void rawTopContentOffsetChanged(float);
-  java.lang.Boolean mCanGoForward;
-  android.widget.FrameLayout mUiView;
-  void nativeResumeContentRendering(long);
-  com.google.vr.ndk.base.GvrUiLayout getUiLayout();
-  void initializeTabForVR();
-  boolean nativeIsDisplayingUrlForTesting(long);
-  boolean mVrBrowsingEnabled;
-  org.chromium.chrome.browser.vr.keyboard.VrInputMethodManagerWrapper mInputMethodManagerWrapper;
-  void access$500(org.chromium.chrome.browser.vr.VrShell, long, org.chromium.chrome.browser.tab.Tab);
-  long mNativeVrShell;
-  void updateHistoryButtonsVisibility();
-  boolean setAsyncReprojectionEnabled(boolean);
-  boolean canRequestRecordAudioPermission();
-  void nativeSetDialogFloating(long, boolean);
-  void nativeShowSoftInput(long, boolean);
-  void setPresentationView(android.view.View);
-  void removeVrRootView();
-  void injectVrRootView();
-  void access$600(org.chromium.chrome.browser.vr.VrShell);
-  void nativeSetDialogBufferSize(long, int, int);
-  com.google.vr.ndk.base.GvrApi getGvrApi();
-  void nativeOnOverlayTextureEmptyChanged(long, boolean);
-  boolean hasUiFinishedLoading();
-  org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver mTabModelSelectorObserver;
-  org.chromium.chrome.browser.ChromeActivity access$1300(org.chromium.chrome.browser.vr.VrShell);
-  void reparentAllTabs(org.chromium.ui.base.WindowAndroid);
-  void nativePerformControllerActionForTesting(long, int, int, float, float);
-  float mLastContentWidth;
-  void nativePerformKeyboardInputForTesting(long, int, java.lang.String);
-  float access$400(org.chromium.chrome.browser.vr.VrShell);
-  org.chromium.chrome.browser.vr.VrShellDelegate mDelegate;
-  org.chromium.chrome.browser.tab.Tab mTab;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell$1 {
-  org.chromium.chrome.browser.vr.VrShell this$0;
-   <init>(org.chromium.chrome.browser.vr.VrShell, android.content.Context);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell$2 {
-  void onContentChanged(org.chromium.chrome.browser.tab.Tab);
-  org.chromium.chrome.browser.vr.VrShell this$0;
-   <init>(org.chromium.chrome.browser.vr.VrShell);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell$3 {
-  org.chromium.chrome.browser.vr.VrShell this$0;
-   <init>(org.chromium.chrome.browser.vr.VrShell);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell$4 {
-  org.chromium.chrome.browser.vr.VrShell this$0;
-   <init>(org.chromium.chrome.browser.vr.VrShell);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell$5 {
-   <init>(org.chromium.chrome.browser.vr.VrShell);
-  org.chromium.chrome.browser.vr.VrShell this$0;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell$5$1 {
-   <init>(org.chromium.chrome.browser.vr.VrShell$5);
-  org.chromium.chrome.browser.vr.VrShell$5 this$1;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell$5$1$1 {
-  int[] val$grantResults;
-  org.chromium.chrome.browser.vr.VrShell$5$1 this$2;
-   <init>(org.chromium.chrome.browser.vr.VrShell$5$1, int[]);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell$6 {
-  org.chromium.chrome.browser.vr.VrShell this$0;
-   <init>(org.chromium.chrome.browser.vr.VrShell);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell$7 {
-  org.chromium.chrome.browser.vr.VrShell this$0;
-   <init>(org.chromium.chrome.browser.vr.VrShell, org.chromium.chrome.browser.tabmodel.TabModelSelector);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShell$UiOperationData {
-  boolean visibility;
-  int elementName;
-  java.lang.Runnable resultCallback;
-  int timeoutMs;
-  int actionType;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate {
-  void requestToExitVrForSearchEnginePromoDialog(org.chromium.chrome.browser.vr.OnExitVrRequestListener, android.app.Activity);
-  void maybeUnregisterVrEntryHook();
-  boolean mExitedDueToUnsupportedMode;
-  org.chromium.chrome.browser.vr.VrShellDelegate access$200();
-  java.lang.Boolean mIsDaydreamCurrentViewer;
-  org.chromium.chrome.browser.vr.VrCoreVersionChecker sVrCoreVersionChecker;
-  boolean access$1302(org.chromium.chrome.browser.vr.VrShellDelegate, boolean);
-  void onVrIntentUnsupported();
-  boolean mPaused;
-  boolean supports2dInVr();
-  void nativeOnLibraryAvailable();
-  boolean isVrBrowsingEnabled();
-  org.chromium.chrome.browser.ChromeActivity mActivity;
-  boolean sRegisteredDaydreamHook;
-  void restoreWindowMode();
-  void swapHostActivity(org.chromium.chrome.browser.ChromeActivity, boolean);
-  boolean onDensityChanged(int, int);
-  void unregisterDaydreamIntent();
-  int mCachedGvrKeyboardPackageVersion;
-  boolean expectedDensityChange();
-  void access$2200(org.chromium.chrome.browser.ChromeActivity);
-  void nativeDisplayActivate(long);
-  void onNativeLibraryAvailable();
-  boolean access$1702(org.chromium.chrome.browser.vr.VrShellDelegate, boolean);
-  boolean onBackPressed();
-  void onExitVrResult(boolean);
-  void lambda$requestToExitVrForSearchEnginePromoDialog$0(org.chromium.chrome.browser.vr.OnExitVrRequestListener);
-  int mExpectedDensityChange;
-  void onPause();
-  boolean isDaydreamReadyDevice();
-  void requestToExitVrAndRunOnSuccess(java.lang.Runnable, int);
-  void exitWebVRAndClearState();
-  void doPreInflationStartup(org.chromium.chrome.browser.ChromeActivity, android.os.Bundle);
-  boolean mVisible;
-  void onStart();
-  boolean cancelStartupAnimationIfNeeded();
-  java.lang.Runnable getVrSettingsButtonListener();
-  java.lang.Integer sVrSupportLevel;
-  boolean mInternalIntentUsedToStartVr;
-  void access$2100(boolean);
-  void nativeRegisterVrAssetsComponent();
-  boolean mProbablyInDon;
-  boolean hasDaydreamSupport();
-  android.app.PendingIntent getEnterVrPendingIntent(org.chromium.chrome.browser.ChromeActivity);
-  boolean mMaybeActivateAfterHeadsetInsertion;
-  boolean mTestWorkaroundDontCancelVrEntryOnResume;
-  boolean mRequestedWebVr;
-  void ensureLifecycleObserverInitialized();
-  boolean access$602(org.chromium.chrome.browser.vr.VrShellDelegate, boolean);
-  org.chromium.chrome.browser.vr.VrShellDelegate sInstance;
-  boolean mActivateFromHeadsetInsertion;
-  void nativeSetPresentResult(long, boolean);
-  org.chromium.chrome.browser.vr.VrShell getVrShell();
-  void shutdownVr(boolean, boolean);
-  boolean isInVrSession();
-  org.chromium.chrome.browser.vr.VrShellDelegate$VrBroadcastReceiver sVrBroadcastReceiver;
-  void initAfterModuleInstall();
-  void promptForFeedback(org.chromium.chrome.browser.tab.Tab);
-  int getVrSupportLevel();
-  org.chromium.chrome.browser.vr.VrShellDelegate$VrLifecycleObserver sVrLifecycleObserver;
-  org.chromium.chrome.browser.vr.VrShellDelegate$VrBroadcastReceiver access$000();
-  void onActivityHidden();
-  void exitWebVRPresent();
-  void access$300();
-  int enterVrInternal();
-  void onActivityHidden(org.chromium.chrome.browser.ChromeActivity);
-  void onMultiWindowModeChanged(boolean);
-  boolean mListeningForWebVrActivate;
-  void onSaveInstanceState(android.os.Bundle);
-  boolean access$900(org.chromium.chrome.browser.vr.VrShellDelegate);
-  boolean access$800(org.chromium.chrome.browser.vr.VrShellDelegate);
-  boolean access$1602(org.chromium.chrome.browser.vr.VrShellDelegate, boolean);
-  void nativeOnPause(long);
-  boolean mDonSucceeded;
-  void destroyVrShell();
-  int mFeedbackFrequency;
-  org.chromium.chrome.browser.vr.VrCoreVersionChecker getVrCoreVersionChecker();
-  void nativeDestroy(long);
-  int access$1900();
-  boolean createVrShell();
-  void promptForKeyboardUpdate();
-  long mNativeVrShellDelegate;
-  void onActivityShown();
-  java.lang.Runnable getVrCloseButtonListener();
-  void requestToExitVr(org.chromium.chrome.browser.vr.OnExitVrRequestListener, int);
-  boolean canEnterVr();
-  boolean isVrBrowsingSupported(org.chromium.chrome.browser.ChromeActivity);
-  boolean sTestVrShellDelegateOnStartup;
-  org.chromium.chrome.browser.vr.VrShellDelegate access$400(org.chromium.chrome.browser.ChromeActivity);
-  org.chromium.chrome.browser.vr.VrShellDelegate getInstance();
-  void registerDaydreamIntent(org.chromium.chrome.browser.ChromeActivity);
-  boolean access$1500(org.chromium.chrome.browser.vr.VrShellDelegate);
-  boolean sRegisteredVrAssetsComponent;
-  boolean isVrBrowsingEnabled(org.chromium.chrome.browser.ChromeActivity, int);
-  boolean access$502(org.chromium.chrome.browser.vr.VrShellDelegate, boolean);
-  boolean access$2600(org.chromium.chrome.browser.vr.VrShellDelegate);
-  void lambda$setListeningForWebVrActivate$1();
-  int mCachedVrCorePackageVersion;
-  void nativeOnResume(long);
-  void maybeSetPresentResult(boolean);
-  boolean mShowingDoffForGvrUpdate;
-  void onBroadcastReceived();
-  void access$1800(org.chromium.chrome.browser.vr.VrShellDelegate);
-  boolean onBackPressedInternal();
-  void maybeUpdateVrSupportLevel();
-  void setVrModeEnabled(android.app.Activity, boolean);
-  void onResume();
-  org.chromium.chrome.browser.vr.VrShellDelegate getInstance(org.chromium.chrome.browser.ChromeActivity);
-  java.lang.Runnable mSettingsButtonListener;
-  void registerVrAssetsComponentIfDaydreamUser(boolean);
-  boolean activitySupportsPresentation(android.app.Activity);
-  void callOnExitVrRequestListener(boolean);
-  boolean mStartedFromVrIntent;
-  void onVrServicesMaybeUpdated();
-  boolean canLaunch2DIntentsInternal();
-  org.chromium.chrome.browser.vr.OnExitVrRequestListener mOnExitVrRequestListener;
-  void maybeRegisterVrEntryHook(org.chromium.chrome.browser.ChromeActivity);
-  boolean hasRecordAudioPermission();
-  boolean onActivityResultWithNative(int, int);
-  int getGvrKeyboardPackageVersion();
-  java.util.Set sVrModeEnabledActivitys;
-  boolean isVrCoreCompatible();
-  boolean isDaydreamCurrentViewerInternal();
-  java.lang.Runnable mCloseButtonListener;
-  void requestToExitVrAndRunOnSuccess(java.lang.Runnable);
-  void nativeRecordVrStartAction(long, int);
-  void removeVrViews();
-  boolean isInVr();
-  boolean mRestoreSystemUiVisibility;
-  void requestToExitVr(org.chromium.chrome.browser.vr.OnExitVrRequestListener);
-  boolean enterVrAfterDon();
-  boolean enterVrIfNecessary();
-  void forceExitVrImmediately();
-  void enterVr(boolean);
-  org.chromium.chrome.browser.vr.VrShell mVrShell;
-  android.os.Handler mClearMaybeActivateHandler;
-  void onExitVrRequestResult(boolean);
-  void setExpectingIntent(boolean);
-  java.lang.Boolean mShowVrServicesUpdatePrompt;
-  boolean showDoff(boolean);
-  boolean isWindowModeCorrectForVr();
-  void rawTopContentOffsetChanged(float);
-  org.chromium.chrome.browser.vr.VrShellDelegate$VrBroadcastReceiver access$002(org.chromium.chrome.browser.vr.VrShellDelegate$VrBroadcastReceiver);
-  boolean access$2500(org.chromium.chrome.browser.vr.VrShellDelegate);
-  void promptForFeedbackIfNeeded(boolean);
-  void onGvrKeyboardMaybeUpdated();
-  void access$2700(org.chromium.chrome.browser.vr.VrShellDelegate, boolean, boolean);
-  boolean $assertionsDisabled;
-  boolean mShowingDaydreamDoff;
-  int getVrCorePackageVersion();
-  void handleDonFlowSuccess();
-  void addVrViews();
-  boolean access$1400(org.chromium.chrome.browser.vr.VrShellDelegate);
-  org.chromium.chrome.browser.ChromeActivity access$700(org.chromium.chrome.browser.vr.VrShellDelegate);
-  void onActivityStateChange(android.app.Activity, int);
-  java.lang.Runnable mPendingExitVrRequest;
-  boolean mNeedsAnimationCancel;
-  void promptToUpdateVrServices();
-  java.lang.Integer mRestoreOrientation;
-  void destroy();
-  void startFeedback(org.chromium.chrome.browser.tab.Tab);
-  void onStop();
-  void maybeHandleVrIntentPreNative(org.chromium.chrome.browser.ChromeActivity, android.content.Intent);
-   <init>(org.chromium.chrome.browser.ChromeActivity);
-  boolean mCancellingEntryAnimation;
-  void onNewVrIntent();
-  boolean maybeExitVrToUpdateVrServices();
-  void access$1100(org.chromium.chrome.browser.vr.VrShellDelegate, long, int);
-  org.chromium.chrome.browser.vr.VrDaydreamApi getVrDaydreamApi();
-  void onActivityShown(org.chromium.chrome.browser.ChromeActivity);
-  boolean isDaydreamCurrentViewer();
-  long nativeInit();
-  void setWindowModeForVr();
-  void access$2300(org.chromium.chrome.browser.tab.Tab);
-  java.util.Set access$100();
-  org.chromium.chrome.browser.vr.VrDaydreamApi sVrDaydreamApi;
-  boolean activitySupportsExitFeedback(android.app.Activity);
-  void requestToExitVrInternal(org.chromium.chrome.browser.vr.OnExitVrRequestListener, int, boolean);
-  void cancelPendingVrEntry();
-  boolean mShowingExitVrPrompt;
-  boolean canRequestRecordAudioPermission();
-  boolean access$1200(org.chromium.chrome.browser.vr.VrShellDelegate);
-  boolean mInVr;
-  boolean mVrBrowserUsed;
-  void updateVrSupportLevel(java.lang.Integer);
-  void runPendingExitVrTask();
-  boolean mDoffOptional;
-  boolean access$2000();
-  void onNewIntentWithNative(org.chromium.chrome.browser.ChromeActivity, android.content.Intent);
-  boolean canLaunch2DIntents();
-  long access$1000(org.chromium.chrome.browser.vr.VrShellDelegate);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$1 {
-  java.lang.Integer doInBackground();
-   <init>(org.chromium.chrome.browser.ChromeActivity);
-  void onPostExecute(java.lang.Integer);
-  org.chromium.base.task.AsyncTask executeOnExecutor(java.util.concurrent.Executor);
-  org.chromium.chrome.browser.ChromeActivity val$activity;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$2 {
-  java.lang.Runnable val$onSuccess;
-   <init>(java.lang.Runnable);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$3 {
-   <init>(org.chromium.chrome.browser.tab.Tab);
-  org.chromium.chrome.browser.tab.Tab val$tab;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$4 {
-   <init>(org.chromium.chrome.browser.vr.VrShellDelegate);
-  org.chromium.chrome.browser.vr.VrShellDelegate this$0;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$5 {
-  org.chromium.chrome.browser.vr.VrShellDelegate this$0;
-   <init>(org.chromium.chrome.browser.vr.VrShellDelegate);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$6 {
-  org.chromium.chrome.browser.vr.VrShellDelegate this$0;
-   <init>(org.chromium.chrome.browser.vr.VrShellDelegate);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$7 {
-   <init>(org.chromium.chrome.browser.vr.VrShellDelegate);
-  org.chromium.chrome.browser.vr.VrShellDelegate this$0;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$8 {
-   <init>(org.chromium.chrome.browser.vr.VrShellDelegate);
-  org.chromium.chrome.browser.vr.VrShellDelegate this$0;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$VrBroadcastReceiver {
-  boolean $assertionsDisabled;
-  java.lang.ref.WeakReference targetActivity();
-   <init>(org.chromium.chrome.browser.ChromeActivity);
-  java.lang.ref.WeakReference mTargetActivity;
-  void unregister();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$VrLifecycleObserver {
-   <init>(org.chromium.chrome.browser.vr.VrShellDelegate$1);
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrShellDelegate$VrUnsupportedException {
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrToast {
-  org.chromium.chrome.browser.vr.VrToastManager mVrToastManager;
-  boolean $assertionsDisabled;
-   <init>(android.content.Context, org.chromium.chrome.browser.vr.VrToastManager);
-  android.widget.TextView findTextViewRecursive(android.view.View);
-  android.view.View getView();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrToastManager {
-  void showToast(java.lang.CharSequence);
-  void cancelToast();
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrUiWidgetFactory {
-  org.chromium.chrome.browser.vr.VrShell mVrShell;
-   <init>(org.chromium.chrome.browser.vr.VrShell, org.chromium.ui.modaldialog.ModalDialogManager);
-  org.chromium.ui.modaldialog.ModalDialogManager mModalDialogManager;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrViewContainer {
-  android.view.View getInputTarget();
-  void removeAllViews();
-  void setLayoutParams(android.view.ViewGroup$LayoutParams);
-  android.view.ViewTreeObserver getViewTreeObserver();
-  boolean $assertionsDisabled;
-  void setSurface(android.view.Surface);
-  void resize(int, int);
-  android.view.Surface mSurface;
-  void drawSuper(android.graphics.Canvas);
-  boolean isDirty();
-  void invalidate();
-  void destroy();
-  int getChildCount();
-  void addView(android.view.View);
-  void setBackgroundColor(int);
-  android.view.ViewTreeObserver$OnPreDrawListener mPredrawListener;
-  android.view.View getChildAt(int);
-   <init>(android.content.Context);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrViewContainer$1 {
-   <init>(org.chromium.chrome.browser.vr.VrViewContainer);
-  org.chromium.chrome.browser.vr.VrViewContainer this$0;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrWindowAndroid {
-  org.chromium.ui.display.DisplayAndroid getDisplay();
-  void onActivityStarted();
-  android.app.Activity activityFromContext(android.content.Context);
-  void onActivityStopped();
-  java.lang.ref.WeakReference getContext();
-  void setAndroidPermissionDelegate(org.chromium.ui.base.AndroidPermissionDelegate);
-  void setVSyncPaused(boolean);
-   <init>(android.content.Context, org.chromium.ui.display.DisplayAndroid);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.VrWindowAndroid$ActivityAndroidPermissionDelegate {
-   <init>(org.chromium.chrome.browser.vr.VrWindowAndroid);
-  org.chromium.chrome.browser.vr.VrWindowAndroid this$0;
-   <init>(org.chromium.chrome.browser.vr.VrWindowAndroid, org.chromium.chrome.browser.vr.VrWindowAndroid$1);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.keyboard.GvrKeyboardLoaderClient {
-  boolean sFailLoadForTesting;
-  com.google.vr.keyboard.IGvrKeyboardLoader sLoader;
-  android.content.Context getRemoteContext(android.content.Context);
-  java.lang.Object getRemoteClassLoader();
-  org.chromium.chrome.browser.vr.keyboard.GvrKeyboardLoaderClient$KeyboardContextWrapper sContextWrapper;
-  com.google.vr.keyboard.IGvrKeyboardLoader getLoader();
-  android.os.IBinder newBinder(java.lang.ClassLoader, java.lang.String);
-  java.lang.ClassLoader sRemoteClassLoader;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.keyboard.GvrKeyboardLoaderClient$KeyboardContextWrapper {
-   <init>(android.content.Context, android.content.Context);
-   <init>(android.content.Context, android.content.Context, org.chromium.chrome.browser.vr.keyboard.GvrKeyboardLoaderClient$1);
-  android.content.Context mKeyboardContext;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.keyboard.TextEditAction {
-  int mType;
-  java.lang.String mText;
-  int mNewCursorPosition;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.keyboard.VrInputMethodManagerWrapper {
-  org.chromium.chrome.browser.vr.keyboard.VrInputMethodManagerWrapper$BrowserKeyboardInterface mKeyboard;
-   <init>(android.content.Context, org.chromium.chrome.browser.vr.keyboard.VrInputMethodManagerWrapper$BrowserKeyboardInterface);
-  android.view.View mView;
-  android.content.Context mContext;
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.vr.keyboard.VrInputMethodManagerWrapper$BrowserKeyboardInterface {
-  void updateIndices(int, int, int, int);
-  void showSoftInput(boolean);
-}
-
--keep,allowobfuscation class org.chromium.chrome.browser.widget.findinpage.FindToolbarManager {
-  void hideToolbar();
-}
-
--keep,allowobfuscation class org.chromium.chrome.vr.R {
-  void onResourcesLoadedString(int);
-  boolean sResourcesDidLoad;
-  void onResourcesLoadedDrawable(int);
-  boolean $assertionsDisabled;
-}
-
--keep,allowobfuscation class org.chromium.chrome.vr.R$drawable {
-  int vr_services;
-}
-
--keep,allowobfuscation class org.chromium.chrome.vr.R$string {
-  int vr_shell_feedback_infobar_description;
-  int vr_services_check_infobar_update_button;
-  int vr_services_check_infobar_update_text;
-  int vr_services_check_infobar_install_text;
-  int vr_services_check_infobar_install_button;
-  int vr_shell_feedback_infobar_feedback_button;
-}
-
--keep,allowobfuscation class org.chromium.content_public.browser.ImeAdapter {
-  void setInputMethodManagerWrapper(org.chromium.content_public.browser.InputMethodManagerWrapper);
-  org.chromium.content_public.browser.InputMethodManagerWrapper createDefaultInputMethodManagerWrapper(android.content.Context);
-  android.view.inputmethod.InputConnection getActiveInputConnection();
-  org.chromium.content_public.browser.ImeAdapter fromWebContents(org.chromium.content_public.browser.WebContents);
-}
-
--keep,allowobfuscation class org.chromium.content_public.browser.LoadUrlParams {
-   <init>(java.lang.String);
-}
-
--keep,allowobfuscation class org.chromium.content_public.browser.MotionEventSynthesizer {
-  org.chromium.content_public.browser.MotionEventSynthesizer create(android.view.View);
-  void setPointer(int, int, int, int, int);
-  void inject(int, int, long);
-}
-
--keep,allowobfuscation class org.chromium.content_public.browser.ScreenOrientationProvider {
-  void setOrientationDelegate(org.chromium.content_public.browser.ScreenOrientationDelegate);
-}
-
--keep,allowobfuscation class org.chromium.content_public.browser.UiThreadTaskTraits {
-  org.chromium.base.task.TaskTraits DEFAULT;
-}
-
--keep,allowobfuscation class org.chromium.content_public.browser.ViewEventSink {
-  void onWindowFocusChanged(boolean);
-  org.chromium.content_public.browser.ViewEventSink from(org.chromium.content_public.browser.WebContents);
-}
-
--keep,allowobfuscation class org.chromium.content_public.browser.WebContents {
-  org.chromium.ui.base.EventForwarder getEventForwarder();
-  void setSize(int, int);
-}
-
--keep,allowobfuscation class org.chromium.device.vr.NonPresentingGvrContext {
-  long mNativeGvrDevice;
-   <init>(long);
-  com.google.vr.ndk.base.GvrApi mGvrApi;
-  void resume();
-  boolean mResumed;
-  com.google.vr.cardboard.DisplaySynchronizer mDisplaySynchronizer;
-  void onDisplayConfigurationChanged();
-  void nativeOnDisplayConfigurationChanged(long);
-}
-
--keep,allowobfuscation class org.chromium.device.vr.NonPresentingGvrContext$1 {
-   <init>(org.chromium.device.vr.NonPresentingGvrContext, android.content.Context, android.view.Display);
-  org.chromium.device.vr.NonPresentingGvrContext this$0;
-}
-
--keep,allowobfuscation class org.chromium.ui.UiUtils {
-  void removeViewFromParent(android.view.View);
-}
-
--keep,allowobfuscation class org.chromium.ui.base.ActivityWindowAndroid {
-  boolean canRequestPermission(java.lang.String);
-  void requestPermissions(java.lang.String[], org.chromium.ui.base.PermissionCallback);
-  boolean hasPermission(java.lang.String);
-  org.chromium.ui.display.DisplayAndroid getDisplay();
-}
-
--keep,allowobfuscation class org.chromium.ui.base.EventForwarder {
-  boolean onGenericMotionEvent(android.view.MotionEvent);
-  boolean dispatchKeyEvent(android.view.KeyEvent);
-}
-
--keep,allowobfuscation class org.chromium.ui.base.PermissionCallback {
-  void onRequestPermissionsResult(java.lang.String[], int[]);
-}
-
--keep,allowobfuscation class org.chromium.ui.base.WindowAndroid {
-   <init>(android.content.Context, org.chromium.ui.display.DisplayAndroid);
-}
-
--keep,allowobfuscation class org.chromium.ui.display.DisplayAndroid {
-  float getDipScale();
-  org.chromium.ui.display.DisplayAndroid getNonMultiDisplay(android.content.Context);
-  float getAndroidUIScaling();
-}
-
--keep,allowobfuscation class org.chromium.ui.display.VirtualDisplayAndroid {
-  void update(android.graphics.Point, java.lang.Float, java.lang.Float, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Boolean, java.lang.Boolean, java.lang.Float, android.view.Display$Mode, java.util.List);
-  void setTo(org.chromium.ui.display.DisplayAndroid);
-  void destroy();
-  org.chromium.ui.display.VirtualDisplayAndroid createVirtualDisplay();
-}
-
--keep,allowobfuscation class org.chromium.ui.modaldialog.ModalDialogManager {
-  void dismissDialog(org.chromium.ui.modelutil.PropertyModel, int);
-  void showDialog(org.chromium.ui.modelutil.PropertyModel, int);
-  void dismissAllDialogs(int);
-   <init>(org.chromium.ui.modaldialog.ModalDialogManager$Presenter, int);
-}
-
--keep,allowobfuscation class org.chromium.ui.modaldialog.ModalDialogManager$Presenter {
-   <init>();
-}
-
--keep,allowobfuscation class org.chromium.ui.modaldialog.ModalDialogProperties {
-  org.chromium.ui.modelutil.PropertyKey[] ALL_KEYS;
-  org.chromium.ui.modelutil.PropertyModel$ReadableObjectPropertyKey CONTROLLER;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey CUSTOM_VIEW;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey NEGATIVE_BUTTON_TEXT;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey MESSAGE;
-  org.chromium.ui.modelutil.PropertyModel$WritableObjectPropertyKey POSITIVE_BUTTON_TEXT;
-}
-
--keep,allowobfuscation class org.chromium.ui.modelutil.PropertyModel$Builder {
-  org.chromium.ui.modelutil.PropertyModel$Builder with(org.chromium.ui.modelutil.PropertyModel$ReadableObjectPropertyKey, java.lang.Object);
-  org.chromium.ui.modelutil.PropertyModel build();
-   <init>(org.chromium.ui.modelutil.PropertyKey[]);
-}
-
--keep,allowobfuscation class org.chromium.ui.modelutil.PropertyModelChangeProcessor {
-  void destroy();
-  org.chromium.ui.modelutil.PropertyModelChangeProcessor create(org.chromium.ui.modelutil.PropertyObservable, java.lang.Object, org.chromium.ui.modelutil.PropertyModelChangeProcessor$ViewBinder);
-}
-
--keep,allowobfuscation class org.chromium.ui.widget.UiWidgetFactory {
-  org.chromium.ui.widget.UiWidgetFactory getInstance();
-   <init>();
-  void setInstance(org.chromium.ui.widget.UiWidgetFactory);
-}
-
--keep,allowobfuscation class org.json.JSONObject {
-  java.lang.Object NULL;
-}
diff --git a/chrome/android/features/vr/vr_module.gni b/chrome/android/features/vr/vr_module.gni
index 0e20f34..5548640 100644
--- a/chrome/android/features/vr/vr_module.gni
+++ b/chrome/android/features/vr/vr_module.gni
@@ -11,7 +11,6 @@
   name = "vr"
   java_deps = [ "//chrome/android/features/vr:java" ]
   android_manifest = "//chrome/android/features/vr/java/AndroidManifest.xml"
-  proguard_async = async_vr
   if (use_native_partitions) {
     native_deps = [ "//chrome/browser/vr:vr_ui" ]
     native_entrypoints = "//chrome/browser/vr/module_exports.lst"
diff --git a/chrome/android/java/res/drawable/hairline_border_card_background_with_inset.xml b/chrome/android/feed/core/java/res/drawable/hairline_border_card_background_with_inset.xml
similarity index 95%
rename from chrome/android/java/res/drawable/hairline_border_card_background_with_inset.xml
rename to chrome/android/feed/core/java/res/drawable/hairline_border_card_background_with_inset.xml
index 0b4c62b..17cb700 100644
--- a/chrome/android/java/res/drawable/hairline_border_card_background_with_inset.xml
+++ b/chrome/android/feed/core/java/res/drawable/hairline_border_card_background_with_inset.xml
@@ -7,7 +7,6 @@
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
-    tools:ignore="UnusedResources"
     android:shape="rectangle" >
     <solid android:color="@color/modern_primary_color" />
     <stroke android:width="1dp" android:color="@color/hairline_stroke_color"/>
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
index 3c45efc..f3cac82 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
@@ -33,7 +33,6 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.GlobalDiscardableReferencePool;
 import org.chromium.chrome.browser.feed.tooltip.BasicTooltipApi;
@@ -49,6 +48,7 @@
 import org.chromium.chrome.browser.ui.widget.displaystyle.UiConfig;
 import org.chromium.chrome.browser.ui.widget.displaystyle.ViewResizer;
 import org.chromium.chrome.browser.util.ViewUtils;
+import org.chromium.chrome.feed.R;
 import org.chromium.ui.UiUtils;
 
 import java.util.Arrays;
diff --git a/chrome/android/java/src/PRESUBMIT.py b/chrome/android/java/src/PRESUBMIT.py
index b3125b8..a8a3d66 100644
--- a/chrome/android/java/src/PRESUBMIT.py
+++ b/chrome/android/java/src/PRESUBMIT.py
@@ -79,7 +79,6 @@
   # general, preference and FRE related UIs are not relevant to VR mode.
   blacklist = (
       BROWSER_ROOT + 'browserservices/ClearDataDialogActivity.java',
-      BROWSER_ROOT + 'init/InvalidStartupDialog.java',
       BROWSER_ROOT + 'password_manager/AccountChooserDialog.java',
       BROWSER_ROOT + 'password_manager/AutoSigninFirstRunDialog.java',
       BROWSER_ROOT + r'preferences[\\\/].*',
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
index 1479763..b3fb992 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser;
 
-import android.app.Activity;
 import android.app.Application;
 import android.content.Context;
 import android.content.Intent;
@@ -13,7 +12,6 @@
 
 import androidx.annotation.Nullable;
 
-import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.BuildConfig;
@@ -25,7 +23,6 @@
 import org.chromium.base.PathUtils;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.annotations.MainDex;
-import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.memory.MemoryPressureMonitor;
 import org.chromium.base.multidex.ChromiumMultiDexInstaller;
 import org.chromium.base.task.AsyncTask;
@@ -42,7 +39,6 @@
 import org.chromium.chrome.browser.dependency_injection.ChromeAppModule;
 import org.chromium.chrome.browser.dependency_injection.DaggerChromeAppComponent;
 import org.chromium.chrome.browser.dependency_injection.ModuleFactoryOverrides;
-import org.chromium.chrome.browser.init.InvalidStartupDialog;
 import org.chromium.chrome.browser.metrics.UmaUtils;
 import org.chromium.chrome.browser.night_mode.SystemNightModeMonitor;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
@@ -202,18 +198,6 @@
                 || level >= TRIM_MEMORY_MODERATE;
     }
 
-    /**
-     * Shows an error dialog following a startup error, and then exits the application.
-     * @param e The exception reported by Chrome initialization.
-     */
-    public static void reportStartupErrorAndExit(final ProcessInitException e) {
-        Activity activity = ApplicationStatus.getLastTrackedFocusedActivity();
-        if (ApplicationStatus.getStateForActivity(activity) == ActivityState.DESTROYED) {
-            return;
-        }
-        InvalidStartupDialog.show(activity, e.getErrorCode());
-    }
-
     @Override
     public void startActivity(Intent intent) {
         startActivity(intent, null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemRow.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemRow.java
index f7ed0d2a..27297e3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemRow.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemRow.java
@@ -81,8 +81,9 @@
             icon = mIconGenerator.generateIconForUrl(mUrl);
             setIconDrawable(new BitmapDrawable(getResources(), icon));
         } else {
-            setIconDrawable(FaviconUtils.createRoundedBitmapDrawable(Bitmap.createScaledBitmap(
-                    icon, mDisplayedIconSize, mDisplayedIconSize, false)));
+            setIconDrawable(FaviconUtils.createRoundedBitmapDrawable(getResources(),
+                    Bitmap.createScaledBitmap(
+                            icon, mDisplayedIconSize, mDisplayedIconSize, false)));
         }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
index 71854a1..9b4bc6c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
@@ -238,7 +238,7 @@
                         Bitmap.createScaledBitmap(image, mFaviconSize, mFaviconSize, true));
             }
 
-            return FaviconUtils.createRoundedBitmapDrawable(
+            return FaviconUtils.createRoundedBitmapDrawable(mContext.getResources(),
                     Bitmap.createScaledBitmap(image, mFaviconSize, mFaviconSize, true));
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 1e9589f29..f1424d71 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -33,7 +33,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ActivityTabTaskDescriptionHelper;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -98,7 +97,7 @@
     @Nullable
     private DynamicModuleCoordinator mDynamicModuleCoordinator;
 
-    private ActivityTabTaskDescriptionHelper mTaskDescriptionHelper;
+    private CustomTabTaskDescriptionHelper mTaskDescriptionHelper;
 
     private CustomTabNightModeStateController mNightModeStateController;
 
@@ -243,7 +242,7 @@
         mConnection.showSignInToastIfNecessary(mSession, getIntent());
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && useSeparateTask()) {
-            mTaskDescriptionHelper = new ActivityTabTaskDescriptionHelper(this,
+            mTaskDescriptionHelper = new CustomTabTaskDescriptionHelper(this,
                     ApiCompatibilityUtils.getColor(getResources(), R.color.default_primary_color));
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
similarity index 95%
rename from chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java
rename to chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
index 50d2783..8ef9332 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
@@ -2,12 +2,13 @@
 // 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;
+package org.chromium.chrome.browser.customtabs;
 
 import android.graphics.Bitmap;
 import android.text.TextUtils;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
@@ -32,12 +33,12 @@
  * <p>
  * The task description is what is shown in Android's Overview/Recents screen for each entry.
  */
-public class ActivityTabTaskDescriptionHelper {
+public class CustomTabTaskDescriptionHelper {
     private final int mDefaultThemeColor;
     private final ChromeActivity mActivity;
     private final TabModelSelector mTabModelSelector;
 
-    private final ActivityTaskDescriptionIconGenerator mIconGenerator;
+    private final CustomTabTaskDescriptionIconGenerator mIconGenerator;
     private final FaviconHelper mFaviconHelper;
 
     private final TabModelSelectorObserver mTabModelSelectorObserver;
@@ -53,13 +54,13 @@
      * @param activity The activity whose descriptions should be updated.
      * @param defaultThemeColor The default theme color to be used if the tab does not override it.
      */
-    public ActivityTabTaskDescriptionHelper(ChromeActivity activity, int defaultThemeColor) {
+    public CustomTabTaskDescriptionHelper(ChromeActivity activity, int defaultThemeColor) {
         mActivity = activity;
         mDefaultThemeColor = defaultThemeColor;
 
         mTabModelSelector = mActivity.getTabModelSelector();
 
-        mIconGenerator = new ActivityTaskDescriptionIconGenerator(activity);
+        mIconGenerator = new CustomTabTaskDescriptionIconGenerator(activity);
         mFaviconHelper = new FaviconHelper();
 
         mTabObserver = new EmptyTabObserver() {
@@ -244,8 +245,7 @@
 
             final String currentUrl = mCurrentTab.getUrl();
             mFaviconHelper.getLocalFaviconImageForURL(
-                    mCurrentTab.getProfile(), mCurrentTab.getUrl(), 0,
-                    (image, iconUrl) -> {
+                    mCurrentTab.getProfile(), mCurrentTab.getUrl(), 0, (image, iconUrl) -> {
                         if (mCurrentTab == null
                                 || !TextUtils.equals(currentUrl, mCurrentTab.getUrl())) {
                             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTaskDescriptionIconGenerator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionIconGenerator.java
similarity index 90%
rename from chrome/android/java/src/org/chromium/chrome/browser/ActivityTaskDescriptionIconGenerator.java
rename to chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionIconGenerator.java
index 7fa7dad..8efabed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTaskDescriptionIconGenerator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionIconGenerator.java
@@ -2,7 +2,7 @@
 // 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;
+package org.chromium.chrome.browser.customtabs;
 
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -11,9 +11,9 @@
 import org.chromium.chrome.browser.ui.widget.RoundedIconGenerator;
 
 /**
- * Generates icons suitable for Activities in the recent tasks list.
+ * Generates icons suitable for Custom Tabs in the recent tasks list.
  */
-public class ActivityTaskDescriptionIconGenerator {
+public class CustomTabTaskDescriptionIconGenerator {
     private static final int APP_ICON_MIN_SIZE_DP = 32;
     private static final int APP_ICON_SIZE_DP = 64;
     private static final int APP_ICON_CORNER_RADIUS_DP = 3;
@@ -38,7 +38,7 @@
      */
     private RoundedIconGenerator mGenerator;
 
-    public ActivityTaskDescriptionIconGenerator(Context context) {
+    public CustomTabTaskDescriptionIconGenerator(Context context) {
         mContext = context;
         mMinSizePx =
                 (int) mContext.getResources().getDisplayMetrics().density * APP_ICON_MIN_SIZE_DP;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java
index 47abec6..0024044 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java
@@ -71,7 +71,7 @@
             drawable = new BitmapDrawable(mResources,
                     mIconGenerator.generateIconForText(mCategoryData.getCategoryName()));
         } else {
-            drawable = ViewUtils.createRoundedBitmapDrawable(
+            drawable = ViewUtils.createRoundedBitmapDrawable(mResources,
                     Bitmap.createScaledBitmap(bitmap, mIconWidthPx, mIconHeightPx, false),
                     mResources.getDimensionPixelSize(R.dimen.experimental_explore_sites_radius));
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
index 6b03f4a..56bbf49 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
@@ -175,7 +175,7 @@
                         mProfile, category.getId(), iconSizePx, (Bitmap image) -> {
                             if (image != null) {
                                 category.setDrawable(ViewUtils.createRoundedBitmapDrawable(
-                                        image, iconSizePx / 2));
+                                        v.getContext().getResources(), image, iconSizePx / 2));
                                 v.renderIcon(category);
                             }
                         });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconUtils.java
index 70e34ba..35f93d8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconUtils.java
@@ -9,7 +9,6 @@
 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ui.widget.RoundedIconGenerator;
 import org.chromium.chrome.browser.util.ViewUtils;
@@ -50,13 +49,14 @@
     /**
      * Creates a {@link RoundedBitmapDrawable} using the provided {@link Bitmap} and a default
      * favicon corner radius.
+     * @param resources The {@link Resources}.
      * @param icon The {@link Bitmap} to round.
      * @return A {@link RoundedBitmapDrawable} for the provided {@link Bitmap}.
      */
-    public static RoundedBitmapDrawable createRoundedBitmapDrawable(Bitmap icon) {
-        Resources resources = ContextUtils.getApplicationContext().getResources();
-        return ViewUtils.createRoundedBitmapDrawable(
-                icon, resources.getDimensionPixelSize(R.dimen.default_favicon_corner_radius));
+    public static RoundedBitmapDrawable createRoundedBitmapDrawable(
+            Resources resources, Bitmap icon) {
+        return ViewUtils.createRoundedBitmapDrawable(resources, icon,
+                resources.getDimensionPixelSize(R.dimen.default_favicon_corner_radius));
     }
 
     private static int getIconColor(Resources resources) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java
index e6df03a7..b1a92a2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheet.java
@@ -33,6 +33,12 @@
          * Navigates to the page associated with the given index.
          */
         void navigateToIndex(int index);
+
+        /**
+         * Sets a runnable to execute when the associated Tab is closed.
+         * @param runnable Runnable to execute.
+         */
+        void setTabCloseRunnable(Runnable runnable);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
index 9771609..6c68a6b6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationSheetCoordinator.java
@@ -82,6 +82,8 @@
     private final int mContentPadding;
     private final View mParentView;
 
+    private final Runnable mCloseRunnable = () -> close(true);
+
     private static class NavigationItemViewBinder {
         public static void bind(PropertyModel model, View view, PropertyKey propertyKey) {
             if (ItemProperties.ICON == propertyKey) {
@@ -166,6 +168,7 @@
 
     private void expandSheet() {
         mBottomSheetController.get().expandSheet();
+        mDelegate.setTabCloseRunnable(mCloseRunnable);
         GestureNavMetrics.recordHistogram("GestureNavigation.Sheet.Viewed", mForward);
     }
 
@@ -226,6 +229,7 @@
     private void close(boolean animate) {
         if (!isHidden()) mBottomSheetController.get().hideContent(this, animate);
         mBottomSheetController.get().getBottomSheet().removeObserver(mSheetObserver);
+        mDelegate.setTabCloseRunnable(null);
         mMediator.clear();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java
index af22c1a..619990c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedSheetDelegate.java
@@ -6,6 +6,7 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.history.HistoryManagerUtils;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.UrlConstants;
 import org.chromium.content_public.browser.NavigationEntry;
@@ -22,6 +23,25 @@
     private final Tab mTab;
     private final String mFullHistoryMenu;
 
+    // TabObserver that monitors tab closing event to close the navigation sheet
+    // together if open. For now this is necessary when closing all incognito tabs
+    // through Android notification.
+    private static class CloseTabObserver extends EmptyTabObserver {
+        private Runnable mCloseRunnable;
+
+        public void setCloseRunnable(Runnable runnable) {
+            mCloseRunnable = runnable;
+        }
+
+        @Override
+        public void onDestroyed(Tab tab) {
+            mCloseRunnable.run();
+            tab.removeObserver(this);
+        }
+    }
+
+    private final CloseTabObserver mCloseTabObserver = new CloseTabObserver();
+
     public TabbedSheetDelegate(Tab tab) {
         mTab = tab;
         mFullHistoryMenu = tab.getActivity().getResources().getString(R.string.show_full_history);
@@ -45,4 +65,14 @@
             mTab.getWebContents().getNavigationController().goToNavigationIndex(index);
         }
     }
+
+    @Override
+    public void setTabCloseRunnable(Runnable runnable) {
+        if (runnable != null) {
+            mCloseTabObserver.setCloseRunnable(runnable);
+            mTab.addObserver(mCloseTabObserver);
+        } else {
+            mTab.removeObserver(mCloseTabObserver);
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
index 9d310b6..2d75eac8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
@@ -169,8 +169,9 @@
             icon = mIconGenerator.generateIconForUrl(getItem().getUrl());
             setIconDrawable(new BitmapDrawable(getResources(), icon));
         } else {
-            setIconDrawable(FaviconUtils.createRoundedBitmapDrawable(Bitmap.createScaledBitmap(
-                    icon, mDisplayedIconSize, mDisplayedIconSize, false)));
+            setIconDrawable(FaviconUtils.createRoundedBitmapDrawable(getResources(),
+                    Bitmap.createScaledBitmap(
+                            icon, mDisplayedIconSize, mDisplayedIconSize, false)));
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index d95507c7..080080a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -33,7 +33,6 @@
 import org.chromium.base.library_loader.LoaderErrors;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.ChromeBaseAppCompatActivity;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.LaunchIntentDispatcher;
@@ -249,9 +248,7 @@
     @CallSuper
     @Override
     public void onStartupFailure() {
-        ProcessInitException e =
-                new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_STARTUP_FAILED);
-        ChromeApplication.reportStartupErrorAndExit(e);
+        throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_STARTUP_FAILED);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/InvalidStartupDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/init/InvalidStartupDialog.java
deleted file mode 100644
index 0c451128..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/InvalidStartupDialog.java
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.init;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.app.FragmentActivity;
-import android.support.v7.app.AlertDialog;
-import android.util.Log;
-
-import org.chromium.base.library_loader.LoaderErrors;
-import org.chromium.chrome.R;
-
-/**
- * Dialog shown when startup fails.
- * <br>
- * Fragments are required to be public with a public empty constructor, hence the visibility.
- */
-public class InvalidStartupDialog extends DialogFragment {
-    private static final String TAG = "InvalidStartupDialog";
-
-    private static final String MESSAGE_KEY = "InvalidStartupErrorKey";
-
-    /**
-     * Shows the invalid startup dialog for a given error code.
-     *
-     * @param activity The activity showing the dialog.
-     * @param errorCode The error code that triggered the failure.
-     */
-    public static void show(Activity activity, int errorCode) {
-        int msg;
-        switch (errorCode) {
-            case LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED:
-                msg = R.string.os_version_missing_features;
-                break;
-            case LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_WRONG_VERSION:
-                msg = R.string.incompatible_libraries;
-                break;
-            default:
-                msg = R.string.native_startup_failed;
-        }
-        final String message = activity.getResources().getString(msg);
-
-        if (!(activity instanceof FragmentActivity)) {
-            Log.e(TAG, "Unable to start chrome due to: " + msg);
-            System.exit(-1);
-            return;
-        }
-
-        Bundle dialogArgs = new Bundle();
-        dialogArgs.putString(MESSAGE_KEY, message);
-
-        InvalidStartupDialog dialog = new InvalidStartupDialog();
-        dialog.setArguments(dialogArgs);
-        dialog.show(((FragmentActivity) activity).getSupportFragmentManager(),
-                "InvalidStartupDialog");
-    }
-
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        Bundle arguments = getArguments();
-        String message = arguments.getString(MESSAGE_KEY, "Failed to start");
-
-        AlertDialog.Builder builder =
-                new AlertDialog.Builder(getActivity(), R.style.Theme_Chromium_AlertDialog);
-        builder.setMessage(message)
-                .setCancelable(true)
-                .setPositiveButton(getResources().getString(android.R.string.ok), null);
-        return builder.create();
-    }
-
-    @Override
-    public void onDismiss(DialogInterface dialog) {
-        super.onDismiss(dialog);
-        System.exit(-1);
-    }
-}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
index 735c2fb..91fa8d75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
@@ -715,7 +715,7 @@
         // TODO(injae): Move shared code between Bookmarks/History/Downloads/here to ViewUtils.java.
         // Also applies to RoundedIconGenerator. crbug.com/829550
         return FaviconUtils.createRoundedBitmapDrawable(
-                Bitmap.createScaledBitmap(image, size, size, true));
+                mActivity.getResources(), Bitmap.createScaledBitmap(image, size, size, true));
     }
 
     private void loadForeignFavicon(final ViewHolder viewHolder, final String url) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java
index 9272bb5..c418a42d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java
@@ -130,7 +130,7 @@
                 icon = mIconGenerator.generateIconForUrl(url);
                 return new BitmapDrawable(getResources(), icon);
             } else {
-                return FaviconUtils.createRoundedBitmapDrawable(
+                return FaviconUtils.createRoundedBitmapDrawable(getResources(),
                         Bitmap.createScaledBitmap(icon, mFaviconSize, mFaviconSize, false));
             }
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
index 437ba62..96e93b0c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
@@ -239,7 +239,8 @@
         if (tile.getSource() == TileSource.EXPLORE) {
             radius = mDesiredIconSize / 2;
         }
-        RoundedBitmapDrawable roundedIcon = ViewUtils.createRoundedBitmapDrawable(icon, radius);
+        RoundedBitmapDrawable roundedIcon =
+                ViewUtils.createRoundedBitmapDrawable(mResources, icon, radius);
         roundedIcon.setAntiAlias(true);
         roundedIcon.setFilterBitmap(true);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 7e30595..122a7b9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -1727,19 +1727,6 @@
     }
 
     /**
-     * Restores a tab either frozen or from state.
-     * TODO(aurimas): investigate reducing the visibility of this method after TabModel refactoring.
-     */
-    public void createHistoricalTab() {
-        if (!isFrozen()) {
-            assert mNativeTabAndroid != 0;
-            TabJni.get().createHistoricalTab(mNativeTabAndroid, Tab.this);
-        } else if (mFrozenContentsState != null) {
-            mFrozenContentsState.createHistoricalTab();
-        }
-    }
-
-    /**
      * Delete navigation entries from frozen state matching the predicate.
      * @param predicate Handle for a deletion predicate interpreted by native code.
      *                  Only valid during this call frame.
@@ -1897,7 +1884,6 @@
                 long intentReceivedTimestamp);
         void setActiveNavigationEntryTitleForUrl(
                 long nativeTabAndroid, Tab caller, String url, String title);
-        void createHistoricalTab(long nativeTabAndroid, Tab caller);
         void loadOriginalImage(long nativeTabAndroid, Tab caller);
         void attachDetachedTab(long nativeTabAndroid, Tab caller);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabState.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabState.java
index c592e4fb..928c896 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabState.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabState.java
@@ -131,14 +131,6 @@
             newState.setVersion(TabState.CONTENTS_STATE_CURRENT_VERSION);
             return newState;
         }
-
-        /**
-         * Creates a WebContents for the ContentsState and adds it as an historical tab, then
-         * deletes the WebContents.
-         */
-        public void createHistoricalTab() {
-            TabStateJni.get().createHistoricalTab(mBuffer, mVersion);
-        }
     }
 
     /** Navigation history of the WebContents. */
@@ -605,6 +597,20 @@
         sChannelNameOverrideForTest = name;
     }
 
+    /**
+     * Creates a historical tab from a tab being closed.
+     */
+    public static void createHistoricalTab(Tab tab) {
+        if (!tab.isFrozen()) {
+            TabStateJni.get().createHistoricalTabFromContents(tab.getWebContents());
+        } else {
+            WebContentsState state = tab.getFrozenContentsState();
+            if (state != null) {
+                TabStateJni.get().createHistoricalTab(state.buffer(), state.version());
+            }
+        }
+    }
+
     @NativeMethods
     interface Natives {
         WebContents restoreContentsFromByteBuffer(
@@ -616,5 +622,6 @@
         String getDisplayTitleFromByteBuffer(ByteBuffer state, int savedStateVersion);
         String getVirtualUrlFromByteBuffer(ByteBuffer state, int savedStateVersion);
         void createHistoricalTab(ByteBuffer state, int savedStateVersion);
+        void createHistoricalTabFromContents(WebContents webContents);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java
index 0e037690..c099316 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java
@@ -12,6 +12,7 @@
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
 import org.chromium.chrome.browser.tab.InterceptNavigationDelegateImpl;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabState;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.MathUtils;
@@ -461,8 +462,9 @@
         }
 
         if (!uponExit && canUndo && supportsPendingClosures()) {
-            for (TabModelObserver obs : mObservers)
+            for (TabModelObserver obs : mObservers) {
                 obs.multipleTabsPendingClosure(closedTabs, true);
+            }
         }
     }
 
@@ -624,7 +626,7 @@
         if (mTabContentManager != null) mTabContentManager.removeTabThumbnail(tab.getId());
         mTabSaver.removeTabFromQueues(tab);
 
-        if (!isIncognito()) tab.createHistoricalTab();
+        if (!isIncognito()) TabState.createHistoricalTab(tab);
 
         for (TabModelObserver obs : mObservers) obs.didCloseTab(tab.getId(), tab.isIncognito());
         if (notifyTabClosureCommitted) {
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index a6bcdbb..a4e7ee5 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2577,17 +2577,6 @@
         YY
       </message>
 
-      <!-- Startup errors -->
-      <message name="IDS_OS_VERSION_MISSING_FEATURES" desc="Error message shown when Chrome fails to run due to an incomplete version of Android.">
-        Critical functionality required to run Chrome is missing; either your Chrome installation is incomplete, or not compatible with this version of Android.
-      </message>
-      <message name="IDS_INCOMPATIBLE_LIBRARIES" desc="Error message shown when Chrome fails to start due to having the wrong version of the native library">
-        Chrome’s components are incompatible with one another. Chrome may be upgrading, please try again in a few minutes. If the problem continues, try uninstalling and re-installing Chrome.
-      </message>
-      <message name="IDS_NATIVE_STARTUP_FAILED" desc="Error message shown when Chrome fails to start for other (unknown) reasons">
-        Chrome failed during startup with an unexpected error.
-      </message>
-
       <!-- First Run strings -->
       <message name="IDS_FRE_ACTIVITY_LABEL" desc="Label for first run dialog in Android Recents.">
         Chrome First Run Experience
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java
index 856f7a7..6444c736 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationSheetTest.java
@@ -107,6 +107,9 @@
         public void navigateToIndex(int index) {
             mNavigationController.goToNavigationIndex(index);
         }
+
+        @Override
+        public void setTabCloseRunnable(Runnable runnable) {}
     }
 
     @Test
diff --git a/chrome/android/modules/chrome_feature_module_tmpl.gni b/chrome/android/modules/chrome_feature_module_tmpl.gni
index 6ac1d0d..cfc20859 100644
--- a/chrome/android/modules/chrome_feature_module_tmpl.gni
+++ b/chrome/android/modules/chrome_feature_module_tmpl.gni
@@ -45,10 +45,6 @@
       deps += _module_desc.java_deps
     }
 
-    if (defined(_module_desc.proguard_async) && _module_desc.proguard_async) {
-      enable_class_deps_output = "${_module_desc.name}_constant_pool_deps.txt"
-    }
-
     # Don't embed more translations than required (http://crbug.com/932017).
     aapt_locale_whitelist = locales
 
diff --git a/chrome/android/modules/chrome_feature_modules.gni b/chrome/android/modules/chrome_feature_modules.gni
index b815f12..05b617d4 100644
--- a/chrome/android/modules/chrome_feature_modules.gni
+++ b/chrome/android/modules/chrome_feature_modules.gni
@@ -28,7 +28,6 @@
 #   native_deps: (Optional) Native code going into module.
 #   native_entrypoints: (Optional) File with list of exposed symbols from native
 #     feature module library.
-#   proguard_async: (Optional) Whether to proguard the module asynchronously.
 #   loadable_modules_32_bit: (Optional) List of additional 32-bit shared
 #     library files going into module if the module is executed in 32 bit.
 #   loadable_modules_64_bit: (Optional) List of additional 64-bit shared
diff --git a/chrome/app/app_management_strings.grdp b/chrome/app/app_management_strings.grdp
index c93367a..d8e5b684 100644
--- a/chrome/app/app_management_strings.grdp
+++ b/chrome/app/app_management_strings.grdp
@@ -85,9 +85,6 @@
   <message name="IDS_APP_MANAGEMENT_STORAGE" desc="Label for the Android storage permission toggle.">
     Storage
   </message>
-  <message name="IDS_APP_MANAGEMENT_SYSTEM_APP_POLICY_STRING" desc="Tooltip label explaining that an app cannot be uninstalled as it is a part of Chrome OS (the operating system).">
-    This app cannot be uninstalled as it is part of Chrome OS.
-  </message>
   <message name="IDS_APP_MANAGEMENT_POLICY_APP_POLICY_STRING" desc="Tooltip label explaining that an app cannot be uninstalled as it has been installed by an adminstrator.">
     This app has been installed by your administrator.
   </message>
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 3cfc20d6..febcb9d 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1610,9 +1610,6 @@
   <message name="IDS_CONTROLLED_SETTING_PARENT" desc="Text displayed in the controlled settings bubble when a setting's value is controlled by user's parent.">
     This setting is managed by a parent.
   </message>
-  <message name="IDS_CONTROLLED_SETTING_CHILD_RESTRICTION" desc="Text displayed in the controlled settings bubble when a setting's value is pre-set because the user is a child.">
-    This setting can't be changed by a child user.
-  </message>
   <message name="IDS_STATUSBAR_DISABLE_SPOKEN_FEEDBACK" desc="The menu option to disable spoken feedback accessibility feature.">
     Disable ChromeVox (spoken feedback)
   </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 67ae427..891661a 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6459,7 +6459,9 @@
         <message name="IDS_CONTROLLED_SETTING_HAS_RECOMMENDATION" desc="Text displayed in the controlled settings bubble when a value is recommended for a setting through policy but is currently overridden by a user-supplied value.">
           Your administrator recommends a specific value for this setting.
         </message>
-
+        <message name="IDS_CONTROLLED_SETTING_CHILD_RESTRICTION" desc="Text displayed in the controlled settings bubble when a setting's value is pre-set because the user is a child.">
+          This setting can't be changed by a child user.
+        </message>
         <!-- Extension install location strings -->
         <message name="IDS_EXTENSIONS_INSTALL_LOCATION_UNKNOWN" desc="The text explaining the the installation location is unknown.">
           Not from Chrome Web Store.
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp
index 223d43e..262da5d 100644
--- a/chrome/app/settings_chromium_strings.grdp
+++ b/chrome/app/settings_chromium_strings.grdp
@@ -26,6 +26,9 @@
     <message name="IDS_SETTINGS_ABOUT_OS" desc="Menu title for the About Chromium OS page.">
       About Chromium OS
     </message>
+    <message name="IDS_SETTINGS_ABOUT_SEE_OS_SETTINGS_FOR_UPDATE_MESSAGE" desc="Message shown to users on Chromium browser settings which alerts the user that OS updates are shown in Chromium OS settings.">
+      To see if your device is up to date, go to <ph name="LINK_BEGIN">&lt;a href="chrome://os-settings/help"&gt;</ph>Chromium OS Settings<ph name="LINK_END">&lt;/a&gt;</ph>
+    </message>
     <message name="IDS_SETTINGS_GET_HELP_USING_CHROME_OS" desc="Text of the button which takes the user to the Chrome help page.">
       Get help with Chromium OS
     </message>
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp
index 2474a21..c63c5b3 100644
--- a/chrome/app/settings_google_chrome_strings.grdp
+++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -26,6 +26,9 @@
     <message name="IDS_SETTINGS_ABOUT_OS" desc="Menu title for the About Chrome OS page.">
       About Chrome OS
     </message>
+    <message name="IDS_SETTINGS_ABOUT_SEE_OS_SETTINGS_FOR_UPDATE_MESSAGE" desc="Message shown to users on Chrome browser settings which alerts the user that OS updates are shown in Chrome OS settings.">
+      To see if your device is up to date, go to <ph name="LINK_BEGIN">&lt;a href="chrome://os-settings/help"&gt;</ph>Chrome OS Settings<ph name="LINK_END">&lt;/a&gt;</ph>
+    </message>
     <message name="IDS_SETTINGS_GET_HELP_USING_CHROME_OS" desc="Text of the button which takes the user to the Chrome help page.">
       Get help with Chrome OS
     </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7444a94b..64deee4 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3910,6 +3910,7 @@
   if (is_desktop_linux) {
     # Desktop linux, doesn't count ChromeOS.
     sources += [
+      "download/download_status_updater_linux.cc",
       "first_run/upgrade_util_linux.cc",
       "first_run/upgrade_util_linux.h",
       "icon_loader_auralinux.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 76e43b6a..6ab8425 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -451,10 +451,6 @@
   "browser_process_impl.cc": [
     "+ui/message_center/message_center.h",
   ],
-  # To share values of UMA enums between product code and tests.
-  "translate_manager_browsertest.cc": [
-    "+services/network/initiator_lock_compatibility.h",
-  ],
   "input_method_manager_impl.cc": [
     "+ash/keyboard/ui/keyboard_ui_controller.h",
   ],
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 3003eff..d54a735 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -623,13 +623,6 @@
      switches::kDisableSiteIsolation, ""},
 };
 
-const FeatureEntry::FeatureParam kEnforceTLS13DowngradeKnownOnly[] = {
-    {"known_roots_only", "true"}};
-
-const FeatureEntry::FeatureVariation kEnforceTLS13DowngradeFeatureVariations[] =
-    {{"(Known Root Only)", kEnforceTLS13DowngradeKnownOnly,
-      base::size(kEnforceTLS13DowngradeKnownOnly), nullptr}};
-
 const FeatureEntry::Choice kForceColorProfileChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
     {flag_descriptions::kForceColorProfileSRGB,
@@ -2387,11 +2380,10 @@
                                  "https://play.google.com/store/apps/"
                                  "details?id=com.android.chrome")},
 #endif  // OS_ANDROID
-    {"enforce-tls13-downgrade", flag_descriptions::kEnforceTLS13DowngradeName,
-     flag_descriptions::kEnforceTLS13DowngradeDescription, kOsAll,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(net::features::kEnforceTLS13Downgrade,
-                                    kEnforceTLS13DowngradeFeatureVariations,
-                                    "EnforceTLS13Downgrade")},
+    {"tls13-hardening-for-local-anchors",
+     flag_descriptions::kTLS13HardeningForLocalAnchorsName,
+     flag_descriptions::kTLS13HardeningForLocalAnchorsDescription, kOsAll,
+     FEATURE_VALUE_TYPE(features::kTLS13HardeningForLocalAnchors)},
     {"enable-tls13-early-data", flag_descriptions::kEnableTLS13EarlyDataName,
      flag_descriptions::kEnableTLS13EarlyDataDescription, kOsAll,
      FEATURE_VALUE_TYPE(net::features::kEnableTLS13EarlyData)},
@@ -3851,6 +3843,11 @@
      flag_descriptions::kEnableImplicitRootScrollerDescription, kOsAll,
      FEATURE_VALUE_TYPE(blink::features::kImplicitRootScroller)},
 
+    {"enable-cssom-view-scroll-coordinates",
+     flag_descriptions::kEnableCSSOMViewScrollCoordinatesName,
+     flag_descriptions::kEnableCSSOMViewScrollCoordinatesDescription, kOsAll,
+     FEATURE_VALUE_TYPE(blink::features::kCSSOMViewScrollCoordinates)},
+
     {"enable-text-fragment-anchor",
      flag_descriptions::kEnableTextFragmentAnchorName,
      flag_descriptions::kEnableTextFragmentAnchorDescription, kOsAll,
@@ -4221,14 +4218,12 @@
      flag_descriptions::kAutofillPruneSuggestionsDescription, kOsAll,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillPruneSuggestions)},
 
-// TODO(https://crbug.com/1010509): Re-enable this in Chrome 80.
-#if 0
     {"allow-popups-during-page-unload",
      flag_descriptions::kAllowPopupsDuringPageUnloadName,
      flag_descriptions::kAllowPopupsDuringPageUnloadDescription,
      kOsAll | kDeprecated,
-     SINGLE_VALUE_TYPE(switches::kAllowPopupsDuringPageUnload)},
-#endif
+     FEATURE_VALUE_TYPE(features::kAllowPopupsDuringPageUnload)},
+
 #if defined(OS_CHROMEOS)
     {"enable-advanced-ppd-attributes",
      flag_descriptions::kEnableAdvancedPpdAttributesName,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index b6b80e8..ee121942 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -547,8 +547,8 @@
 const base::Feature kTabReparenting{"TabReparenting",
                                     base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kTabSwitcherLongpressMenu{
-    "TabSwitcherLongpressMenu", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTabSwitcherLongpressMenu{"TabSwitcherLongpressMenu",
+                                              base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kTabSwitcherOnReturn{"TabSwitcherOnReturn",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index aab5af5c..87ba65d 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/profiles/profile_android.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
-#include "chrome/browser/sessions/tab_restore_service_factory.h"
 #include "chrome/browser/sync/glue/synced_tab_delegate_android.h"
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/browser/ui/android/context_menu_helper.h"
@@ -40,8 +39,6 @@
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tab_helpers.h"
 #include "chrome/common/url_constants.h"
-#include "components/sessions/content/content_live_tab.h"
-#include "components/sessions/core/tab_restore_service.h"
 #include "components/url_formatter/url_fixer.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_agent_host.h"
@@ -429,34 +426,6 @@
     entry->SetTitle(title);
 }
 
-// static
-void TabAndroid::CreateHistoricalTabFromContents(WebContents* web_contents) {
-  DCHECK(web_contents);
-
-  sessions::TabRestoreService* service =
-      TabRestoreServiceFactory::GetForProfile(
-          Profile::FromBrowserContext(web_contents->GetBrowserContext()));
-  if (!service)
-    return;
-
-  // Exclude internal pages from being marked as recent when they are closed.
-  const GURL& tab_url = web_contents->GetURL();
-  if (tab_url.SchemeIs(content::kChromeUIScheme) ||
-      tab_url.SchemeIs(chrome::kChromeNativeScheme) ||
-      tab_url.SchemeIs(url::kAboutScheme)) {
-    return;
-  }
-
-  // TODO(jcivelli): is the index important?
-  service->CreateHistoricalTab(
-      sessions::ContentLiveTab::GetForWebContents(web_contents), -1);
-}
-
-void TabAndroid::CreateHistoricalTab(JNIEnv* env,
-                                     const JavaParamRef<jobject>& obj) {
-  TabAndroid::CreateHistoricalTabFromContents(web_contents());
-}
-
 void TabAndroid::LoadOriginalImage(JNIEnv* env,
                                    const JavaParamRef<jobject>& obj) {
   content::RenderFrameHost* render_frame_host =
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index 2cbbee6..1bdde32 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -161,12 +161,6 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
-  void CreateHistoricalTab(JNIEnv* env,
-                           const base::android::JavaParamRef<jobject>& obj);
-
-  static void CreateHistoricalTabFromContents(
-      content::WebContents* web_contents);
-
   void LoadOriginalImage(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj);
 
diff --git a/chrome/browser/android/tab_state.cc b/chrome/browser/android/tab_state.cc
index 36be8cc..2b02c577 100644
--- a/chrome/browser/android/tab_state.cc
+++ b/chrome/browser/android/tab_state.cc
@@ -19,9 +19,13 @@
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/sessions/tab_restore_service_factory.h"
+#include "chrome/common/url_constants.h"
+#include "components/sessions/content/content_live_tab.h"
 #include "components/sessions/content/content_serialized_navigation_builder.h"
 #include "components/sessions/core/serialized_navigation_entry.h"
 #include "components/sessions/core/session_command.h"
+#include "components/sessions/core/tab_restore_service.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/restore_type.h"
@@ -374,6 +378,27 @@
   return web_contents.release();
 }
 
+void CreateHistoricalTab(content::WebContents* web_contents) {
+  DCHECK(web_contents);
+
+  sessions::TabRestoreService* service =
+      TabRestoreServiceFactory::GetForProfile(
+          Profile::FromBrowserContext(web_contents->GetBrowserContext()));
+  if (!service)
+    return;
+
+  // Exclude internal pages from being marked as recent when they are closed.
+  const GURL& tab_url = web_contents->GetURL();
+  if (tab_url.SchemeIs(content::kChromeUIScheme) ||
+      tab_url.SchemeIs(chrome::kChromeNativeScheme) ||
+      tab_url.SchemeIs(url::kAboutScheme)) {
+    return;
+  }
+
+  // TODO(jcivelli): is the index important?
+  service->CreateHistoricalTab(
+      sessions::ContentLiveTab::GetForWebContents(web_contents), -1);
+}
 }  // anonymous namespace
 
 ScopedJavaLocalRef<jobject> WebContentsState::GetContentsStateAsByteBuffer(
@@ -612,5 +637,14 @@
       WebContentsState::RestoreContentsFromByteBuffer(
           env, state, saved_state_version, true)));
   if (web_contents.get())
-    TabAndroid::CreateHistoricalTabFromContents(web_contents.get());
+    CreateHistoricalTab(web_contents.get());
+}
+
+// static
+static void JNI_TabState_CreateHistoricalTabFromContents(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jweb_contents) {
+  auto* web_contents = content::WebContents::FromJavaWebContents(jweb_contents);
+  if (web_contents)
+    CreateHistoricalTab(web_contents);
 }
diff --git a/chrome/browser/android/vr/BUILD.gn b/chrome/browser/android/vr/BUILD.gn
index 497d92b..aab2e058 100644
--- a/chrome/browser/android/vr/BUILD.gn
+++ b/chrome/browser/android/vr/BUILD.gn
@@ -207,14 +207,6 @@
   ]
 
   java_files = [ "//chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreShimImpl.java" ]
-
-  # TODO(crbug.com/938909): chromium_code.flags is not used as a proguard
-  # config when proguarding asynchronously. This results in AR crashing
-  # chrome when AR is an async DFM. Should implement a more scalable
-  # solution to including chromium_code.flags with all async DFMs.
-  if (async_ar) {
-    proguard_configs = [ "//base/android/proguard/chromium_code.flags" ]
-  }
 }
 
 if (enable_arcore) {
diff --git a/chrome/browser/apps/app_service/app_service_metrics.cc b/chrome/browser/apps/app_service/app_service_metrics.cc
index fd1bdca6..1f43c42 100644
--- a/chrome/browser/apps/app_service/app_service_metrics.cc
+++ b/chrome/browser/apps/app_service/app_service_metrics.cc
@@ -148,4 +148,26 @@
     RecordBuiltInAppLaunch(BuiltInAppName::kPluginVm, launch_source);
 }
 
+void RecordBuiltInAppSearchResult(const std::string& app_id) {
+  if (app_id == ash::kInternalAppIdKeyboardShortcutViewer) {
+    UMA_HISTOGRAM_ENUMERATION("Apps.AppListSearchResultInternalApp.Show",
+                              BuiltInAppName::kKeyboardShortcutViewer);
+  } else if (app_id == ash::kReleaseNotesAppId) {
+    UMA_HISTOGRAM_ENUMERATION("Apps.AppListSearchResultInternalApp.Show",
+                              BuiltInAppName::kReleaseNotes);
+  } else if (app_id == ash::kInternalAppIdCamera) {
+    UMA_HISTOGRAM_ENUMERATION("Apps.AppListSearchResultInternalApp.Show",
+                              BuiltInAppName::kCamera);
+  } else if (app_id == ash::kInternalAppIdDiscover) {
+    UMA_HISTOGRAM_ENUMERATION("Apps.AppListSearchResultInternalApp.Show",
+                              BuiltInAppName::kDiscover);
+  } else if (app_id == ash::kInternalAppIdSettings) {
+    UMA_HISTOGRAM_ENUMERATION("Apps.AppListSearchResultInternalApp.Show",
+                              BuiltInAppName::kSettings);
+  } else if (app_id == plugin_vm::kPluginVmAppId) {
+    UMA_HISTOGRAM_ENUMERATION("Apps.AppListSearchResultInternalApp.Show",
+                              BuiltInAppName::kPluginVm);
+  }
+}
+
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/app_service_metrics.h b/chrome/browser/apps/app_service/app_service_metrics.h
index 90c4fa7..8537858 100644
--- a/chrome/browser/apps/app_service/app_service_metrics.h
+++ b/chrome/browser/apps/app_service/app_service_metrics.h
@@ -15,6 +15,8 @@
 void RecordAppLaunch(const std::string& app_id,
                      apps::mojom::LaunchSource launch_source);
 
+void RecordBuiltInAppSearchResult(const std::string& app_id);
+
 }  // namespace apps
 
 #endif  // CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_METRICS_H_
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc
index f1092e9..685de53 100644
--- a/chrome/browser/apps/app_service/arc_apps.cc
+++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -23,7 +23,6 @@
 #include "chrome/services/app_service/public/cpp/intent_filter_util.h"
 #include "components/arc/app_permissions/arc_app_permissions_bridge.h"
 #include "components/arc/arc_service_manager.h"
-#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/mojom/app_permissions.mojom.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "content/public/browser/system_connector.h"
diff --git a/chrome/browser/apps/app_service/arc_apps.h b/chrome/browser/apps/app_service/arc_apps.h
index f2e30e2..49c69f83d 100644
--- a/chrome/browser/apps/app_service/arc_apps.h
+++ b/chrome/browser/apps/app_service/arc_apps.h
@@ -18,6 +18,7 @@
 #include "chrome/browser/apps/app_service/icon_key_util.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/services/app_service/public/mojom/app_service.mojom.h"
+#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/intent_helper/arc_intent_helper_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -26,10 +27,6 @@
 
 class Profile;
 
-namespace arc {
-class ArcIntentHelperBridge;
-}
-
 namespace apps {
 
 class AppServiceProxy;
diff --git a/chrome/browser/apps/app_service/extension_apps.cc b/chrome/browser/apps/app_service/extension_apps.cc
index 76653cc..04d7fcf0 100644
--- a/chrome/browser/apps/app_service/extension_apps.cc
+++ b/chrome/browser/apps/app_service/extension_apps.cc
@@ -40,12 +40,9 @@
 #include "chrome/services/app_service/public/cpp/intent_filter_util.h"
 #include "chrome/services/app_service/public/mojom/types.mojom.h"
 #include "components/arc/arc_service_manager.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/switches.h"
@@ -153,12 +150,7 @@
     const mojo::Remote<apps::mojom::AppService>& app_service,
     Profile* profile,
     apps::mojom::AppType app_type)
-    : profile_(profile),
-      prefs_observer_(this),
-      registry_observer_(this),
-      content_settings_observer_(this),
-      app_type_(app_type),
-      arc_prefs_(nullptr) {
+    : profile_(profile), app_type_(app_type) {
   Initialize(app_service);
 }
 
diff --git a/chrome/browser/apps/app_service/extension_apps.h b/chrome/browser/apps/app_service/extension_apps.h
index 3ceaa8b5..5852c4b 100644
--- a/chrome/browser/apps/app_service/extension_apps.h
+++ b/chrome/browser/apps/app_service/extension_apps.h
@@ -16,7 +16,9 @@
 #include "chrome/services/app_service/public/mojom/app_service.mojom.h"
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_prefs_observer.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -157,12 +159,12 @@
   Profile* profile_;
 
   ScopedObserver<extensions::ExtensionPrefs, extensions::ExtensionPrefsObserver>
-      prefs_observer_;
+      prefs_observer_{this};
   ScopedObserver<extensions::ExtensionRegistry,
                  extensions::ExtensionRegistryObserver>
-      registry_observer_;
+      registry_observer_{this};
   ScopedObserver<HostContentSettingsMap, content_settings::Observer>
-      content_settings_observer_;
+      content_settings_observer_{this};
 
   apps_util::IncrementingIconKeyFactory icon_key_factory_;
 
@@ -171,7 +173,7 @@
   using EnableFlowPtr = std::unique_ptr<ExtensionAppsEnableFlow>;
   std::map<std::string, EnableFlowPtr> enable_flow_map_;
 
-  ArcAppListPrefs* arc_prefs_;
+  ArcAppListPrefs* arc_prefs_ = nullptr;
 
   base::WeakPtrFactory<ExtensionApps> weak_factory_{this};
 
diff --git a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_api.cc b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_api.cc
index a4f1f9c..6cc86274 100644
--- a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_api.cc
+++ b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_api.cc
@@ -28,7 +28,7 @@
 }
 
 ArcAppsPrivateAPI::ArcAppsPrivateAPI(content::BrowserContext* context)
-    : context_(context), scoped_prefs_observer_(this) {
+    : context_(context) {
   extensions::EventRouter::Get(context_)->RegisterObserver(
       this, api::arc_apps_private::OnInstalled::kEventName);
 }
diff --git a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_api.h b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_api.h
index 61a7bae..bf96e6a 100644
--- a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_api.h
+++ b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_api.h
@@ -47,7 +47,8 @@
 
   content::BrowserContext* const context_;
 
-  ScopedObserver<ArcAppListPrefs, ArcAppsPrivateAPI> scoped_prefs_observer_;
+  ScopedObserver<ArcAppListPrefs, ArcAppListPrefs::Observer>
+      scoped_prefs_observer_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ArcAppsPrivateAPI);
 };
diff --git a/chrome/browser/availability/availability_prober.cc b/chrome/browser/availability/availability_prober.cc
index b758c32..2d249c1f 100644
--- a/chrome/browser/availability/availability_prober.cc
+++ b/chrome/browser/availability/availability_prober.cc
@@ -43,6 +43,8 @@
 const char kCachePrefKeyPrefix[] = "Availability.Prober.cache";
 
 const char kSuccessHistogram[] = "Availability.Prober.DidSucceed";
+const char kSuccessAfterReportedFailure[] =
+    "Availability.Prober.DidSucceed.AfterReportedFailure";
 const char kFinalResultHistogram[] = "Availability.Prober.FinalState";
 const char kTimeUntilSuccess[] = "Availability.Prober.TimeUntilSuccess";
 const char kTimeUntilFailure[] = "Availability.Prober.TimeUntilFailure";
@@ -279,6 +281,7 @@
       network_connection_tracker_(nullptr),
       pref_service_(pref_service),
       url_loader_factory_(url_loader_factory),
+      reported_external_failure_(false),
       weak_factory_(this) {
   DCHECK(delegate_);
 
@@ -356,6 +359,7 @@
   retry_timer_.reset();
   timeout_timer_.reset();
   url_loader_.reset();
+  reported_external_failure_ = false;
 #if defined(OS_ANDROID)
   application_status_listener_.reset();
 #endif
@@ -615,6 +619,13 @@
   return entry.value().is_success();
 }
 
+void AvailabilityProber::ReportExternalFailureAndRetry() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  RecordProbeResult(false);
+  reported_external_failure_ = true;
+  SendNowIfInactive(false);
+}
+
 void AvailabilityProber::SetOnCompleteCallback(
     AvailabilityProberOnCompleteCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -654,6 +665,13 @@
       base::HistogramBase::kUmaTargetedHistogramFlag)
       ->Add(success);
 
+  if (reported_external_failure_) {
+    base::BooleanHistogram::FactoryGet(
+        AppendNameToHistogram(kSuccessAfterReportedFailure),
+        base::HistogramBase::kUmaTargetedHistogramFlag)
+        ->Add(success);
+  }
+
   // The callback may delete |this| so run it in a post task.
   if (on_complete_callback_) {
     base::PostTask(FROM_HERE, {content::BrowserThread::UI},
diff --git a/chrome/browser/availability/availability_prober.h b/chrome/browser/availability/availability_prober.h
index 364bacf..0258c00 100644
--- a/chrome/browser/availability/availability_prober.h
+++ b/chrome/browser/availability/availability_prober.h
@@ -182,6 +182,11 @@
   // it was successful. It is safe to delete |this| during the callback.
   void SetOnCompleteCallback(AvailabilityProberOnCompleteCallback callback);
 
+  // Called when some other network request to the same endpoint has failed and
+  // the probe should be reattempted. Also records this event as a probe
+  // failure.
+  void ReportExternalFailureAndRetry();
+
  protected:
   // Exposes |tick_clock| and |clock| for testing.
   AvailabilityProber(
@@ -315,6 +320,11 @@
   // bool to indicate success of the completed probe.
   AvailabilityProberOnCompleteCallback on_complete_callback_;
 
+  // This is set after a call to |ReportExternalFailureAndRetry| and cleared
+  // when the next probe completes. This state is kept for histogram recording
+  // of success after a reported failure.
+  bool reported_external_failure_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<AvailabilityProber> weak_factory_{this};
diff --git a/chrome/browser/availability/availability_prober_unittest.cc b/chrome/browser/availability/availability_prober_unittest.cc
index 99040e4..d948196 100644
--- a/chrome/browser/availability/availability_prober_unittest.cc
+++ b/chrome/browser/availability/availability_prober_unittest.cc
@@ -908,3 +908,54 @@
   EXPECT_TRUE(prober->LastProbeWasSuccessful().value());
   EXPECT_FALSE(prober->is_active());
 }
+
+TEST_F(AvailabilityProberTest, ReportExternalFailure_WhileIdle) {
+  base::HistogramTester histogram_tester;
+  std::unique_ptr<AvailabilityProber> prober = NewProber();
+  EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
+  EXPECT_FALSE(prober->is_active());
+
+  prober->ReportExternalFailureAndRetry();
+  EXPECT_FALSE(prober->LastProbeWasSuccessful().value());
+  EXPECT_TRUE(prober->is_active());
+
+  VerifyRequest();
+  MakeResponseAndWait(net::HTTP_OK, net::OK);
+  EXPECT_TRUE(prober->LastProbeWasSuccessful().value());
+  EXPECT_FALSE(prober->is_active());
+
+  histogram_tester.ExpectBucketCount("Availability.Prober.DidSucceed.Litepages",
+                                     true, 1);
+  histogram_tester.ExpectBucketCount("Availability.Prober.DidSucceed.Litepages",
+                                     false, 1);
+  histogram_tester.ExpectUniqueSample(
+      "Availability.Prober.DidSucceed.AfterReportedFailure.Litepages", true, 1);
+}
+
+TEST_F(AvailabilityProberTest, ReportExternalFailure_WhileActive) {
+  base::HistogramTester histogram_tester;
+  std::unique_ptr<AvailabilityProber> prober = NewProber();
+  EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
+  EXPECT_FALSE(prober->is_active());
+
+  prober->SendNowIfInactive(false);
+  EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt);
+  EXPECT_TRUE(prober->is_active());
+  VerifyRequest();
+
+  prober->ReportExternalFailureAndRetry();
+  EXPECT_FALSE(prober->LastProbeWasSuccessful().value());
+  EXPECT_TRUE(prober->is_active());
+  VerifyRequest();
+
+  MakeResponseAndWait(net::HTTP_OK, net::OK);
+  EXPECT_TRUE(prober->LastProbeWasSuccessful().value());
+  EXPECT_FALSE(prober->is_active());
+
+  histogram_tester.ExpectBucketCount("Availability.Prober.DidSucceed.Litepages",
+                                     true, 1);
+  histogram_tester.ExpectBucketCount("Availability.Prober.DidSucceed.Litepages",
+                                     false, 1);
+  histogram_tester.ExpectUniqueSample(
+      "Availability.Prober.DidSucceed.AfterReportedFailure.Litepages", true, 1);
+}
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.cc b/chrome/browser/background_sync/background_sync_controller_impl.cc
index 17abfb9b..f221d68 100644
--- a/chrome/browser/background_sync/background_sync_controller_impl.cc
+++ b/chrome/browser/background_sync/background_sync_controller_impl.cc
@@ -35,6 +35,8 @@
 const char BackgroundSyncControllerImpl::kRelyOnAndroidNetworkDetection[] =
     "rely_on_android_network_detection";
 #endif
+const char BackgroundSyncControllerImpl::kKeepBrowserAwakeParameterName[] =
+    "keep_browser_awake_till_events_complete";
 const char BackgroundSyncControllerImpl::kMaxAttemptsParameterName[] =
     "max_sync_attempts";
 const char BackgroundSyncControllerImpl::
@@ -112,6 +114,11 @@
     parameters->disable = true;
   }
 
+  if (base::LowerCaseEqualsASCII(field_params[kKeepBrowserAwakeParameterName],
+                                 "true")) {
+    parameters->keep_browser_awake_till_events_complete = true;
+  }
+
   if (base::Contains(field_params,
                      kMaxAttemptsWithNotificationPermissionParameterName)) {
     int max_attempts;
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.h b/chrome/browser/background_sync/background_sync_controller_impl.h
index a827f30..e25d0ee 100644
--- a/chrome/browser/background_sync/background_sync_controller_impl.h
+++ b/chrome/browser/background_sync/background_sync_controller_impl.h
@@ -42,6 +42,7 @@
  public:
   static const char kFieldTrialName[];
   static const char kDisabledParameterName[];
+  static const char kKeepBrowserAwakeParameterName[];
   static const char kMaxAttemptsParameterName[];
   static const char kRelyOnAndroidNetworkDetection[];
   static const char kMaxAttemptsWithNotificationPermissionParameterName[];
diff --git a/chrome/browser/banners/app_banner_metrics.h b/chrome/browser/banners/app_banner_metrics.h
index ecf4b5f12..3235263 100644
--- a/chrome/browser/banners/app_banner_metrics.h
+++ b/chrome/browser/banners/app_banner_metrics.h
@@ -32,8 +32,8 @@
 enum InstallEvent {
   INSTALL_EVENT_MIN = 20,
   INSTALL_EVENT_NATIVE_APP_INSTALL_TRIGGERED = 21,
-  INSTALL_EVENT_NATIVE_APP_INSTALL_STARTED = 22,
-  INSTALL_EVENT_NATIVE_APP_INSTALL_COMPLETED = 23,
+  // Deprecated: INSTALL_EVENT_NATIVE_APP_INSTALL_STARTED = 22,
+  // Deprecated: INSTALL_EVENT_NATIVE_APP_INSTALL_COMPLETED = 23,
   INSTALL_EVENT_WEB_APP_INSTALLED = 24,
   INSTALL_EVENT_MAX = 25,
 };
@@ -46,7 +46,7 @@
   DISMISS_EVENT_BANNER_CLICK = 43,
   DISMISS_EVENT_BANNER_SWIPE = 44,
   DISMISS_EVENT_CLOSE_BUTTON = 45,
-  DISMISS_EVENT_INSTALL_TIMEOUT = 46,
+  // Deprecated: DISMISS_EVENT_INSTALL_TIMEOUT = 46,
   DISMISS_EVENT_DISMISSED = 47,
   DISMISS_EVENT_AMBIENT_INFOBAR_DISMISSED = 48,
   DISMISS_EVENT_MAX = 49,
diff --git a/chrome/browser/banners/app_banner_ui_delegate_android.cc b/chrome/browser/banners/app_banner_ui_delegate_android.cc
index a733b0c..e42e450 100644
--- a/chrome/browser/banners/app_banner_ui_delegate_android.cc
+++ b/chrome/browser/banners/app_banner_ui_delegate_android.cc
@@ -18,8 +18,6 @@
 #include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/browser_process.h"
-#include "components/rappor/public/rappor_utils.h"
-#include "components/rappor/rappor_service_impl.h"
 #include "components/url_formatter/elide_url.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/gfx/android/java_bitmap.h"
@@ -133,26 +131,6 @@
   return should_close_banner;
 }
 
-void AppBannerUiDelegateAndroid::OnNativeAppInstallStarted(
-    content::WebContents* web_contents) {
-  AppBannerSettingsHelper::RecordBannerEvent(
-      web_contents, web_contents->GetVisibleURL(), package_name_,
-      AppBannerSettingsHelper::APP_BANNER_EVENT_DID_ADD_TO_HOMESCREEN,
-      AppBannerManager::GetCurrentTime());
-
-  TrackInstallEvent(INSTALL_EVENT_NATIVE_APP_INSTALL_STARTED);
-  rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(),
-                                          "AppBanner.NativeApp.Installed",
-                                          web_contents->GetURL());
-}
-
-void AppBannerUiDelegateAndroid::OnNativeAppInstallFinished(bool success) {
-  if (success)
-    TrackInstallEvent(INSTALL_EVENT_NATIVE_APP_INSTALL_COMPLETED);
-  else
-    TrackDismissEvent(DISMISS_EVENT_INSTALL_TIMEOUT);
-}
-
 void AppBannerUiDelegateAndroid::OnUiCancelled(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& obj) {
diff --git a/chrome/browser/banners/app_banner_ui_delegate_android.h b/chrome/browser/banners/app_banner_ui_delegate_android.h
index e707d50..e2848313 100644
--- a/chrome/browser/banners/app_banner_ui_delegate_android.h
+++ b/chrome/browser/banners/app_banner_ui_delegate_android.h
@@ -74,14 +74,6 @@
   // the installation UI should be dismissed.
   bool InstallApp(content::WebContents* web_contents);
 
-  // Called by the UI layer to indicate that a native app has begun
-  // installation.
-  void OnNativeAppInstallStarted(content::WebContents* web_contents);
-
-  // Called by the UI layer to indicate that a native app has finished
-  // installation.
-  void OnNativeAppInstallFinished(bool success);
-
   // Called through the JNI to indicate that the user has dismissed the
   // installation UI.
   void OnUiCancelled(JNIEnv* env,
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 6fd4bf1..dc3a436 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -2840,13 +2840,11 @@
   auto* content_setting_registry =
       content_settings::ContentSettingsRegistry::GetInstance();
 
-#if !defined(OS_ANDROID)
   auto* history_service =
       HistoryServiceFactory::GetForProfileWithoutCreating(profile);
   // Create a safe_browsing::VerdictCacheManager that will handle deletion of
   // CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION entries.
   safe_browsing::VerdictCacheManager sb_cache_manager(history_service, map);
-#endif  // !defined(OS_ANDROID)
 
   GURL url("https://example.com");
 
diff --git a/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc b/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc
index 187f990..9fbebfc 100644
--- a/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc
+++ b/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc
@@ -76,9 +76,6 @@
     content::WebContentsTester* web_contents_tester =
         content::WebContentsTester::For(web_contents());
     web_contents_tester->NavigateAndCommit(GURL(kStartUrl));
-    content::RenderFrameHostTester* rfh_tester =
-        content::RenderFrameHostTester::For(main_rfh());
-    rfh_tester->SimulateNavigationStop();
 
     tab_helper_.reset(new CaptivePortalTabHelper(web_contents()));
     tab_helper_->profile_ = nullptr;
@@ -139,8 +136,6 @@
     EXPECT_CALL(mock_reloader(), OnAbort()).Times(1);
     navigation->Fail(net::ERR_TIMED_OUT);
     navigation->AbortCommit();
-    content::RenderFrameHostTester::For(navigation->GetFinalRenderFrameHost())
-        ->SimulateNavigationStop();
 
     // Make sure that above call resulted in abort, for tests that continue
     // after the abort.
@@ -180,17 +175,14 @@
 
 TEST_F(CaptivePortalTabHelperTest, HttpSuccess) {
   SimulateSuccess(GURL(kHttpUrl));
-  content::RenderFrameHostTester::For(main_rfh())->SimulateNavigationStop();
 }
 
 TEST_F(CaptivePortalTabHelperTest, HttpTimeout) {
   SimulateTimeout(GURL(kHttpUrl));
-  content::RenderFrameHostTester::For(main_rfh())->SimulateNavigationStop();
 }
 
 TEST_F(CaptivePortalTabHelperTest, HttpsSuccess) {
   SimulateSuccess(GURL(kHttpsUrl));
-  content::RenderFrameHostTester::For(main_rfh())->SimulateNavigationStop();
   EXPECT_FALSE(tab_helper()->IsLoginTab());
 }
 
@@ -237,7 +229,6 @@
 // a cross-process one.
 TEST_F(CaptivePortalTabHelperTest, HttpsAbortTimeoutForCrossProcess) {
   SimulateSuccess(GURL(kHttpsUrl));
-  content::RenderFrameHostTester::For(main_rfh())->SimulateNavigationStop();
 
   SimulateAbortTimeout(GURL(kHttpsUrl));
   // Make sure no state was carried over from the timeout or the abort.
@@ -272,11 +263,6 @@
   // The cross-process navigation fails.
   cross_process_navigation->Fail(net::ERR_FAILED);
 
-  // The same-site navigation finally stops.
-  content::RenderFrameHostTester::For(
-      same_site_navigation->GetFinalRenderFrameHost())
-      ->SimulateNavigationStop();
-
   EXPECT_CALL(mock_reloader(), OnLoadCommitted(net::ERR_FAILED)).Times(1);
   cross_process_navigation->CommitErrorPage();
 }
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index f491934..c162d840 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1680,12 +1680,6 @@
     *referrer = content::Referrer();
     *initiator_origin = base::nullopt;
   }
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-  ChromeContentBrowserClientExtensionsPart::OverrideNavigationParams(
-      site_instance, transition, is_renderer_initiated, referrer,
-      initiator_origin);
-#endif
 }
 
 bool ChromeContentBrowserClient::ShouldStayInParentProcessForNTP(
@@ -1857,30 +1851,7 @@
 }
 
 bool ChromeContentBrowserClient::ShouldDisableSiteIsolation() {
-  // Using 1077 rather than 1024 because 1) it helps ensure that devices with
-  // exactly 1GB of RAM won't get included because of inaccuracies or off-by-one
-  // errors and 2) this is the bucket boundary in Memory.Stats.Win.TotalPhys2.
-  // See also https://crbug.com/844118.
-  constexpr int kDefaultMemoryThresholdMb = 1077;
-
-  // TODO(acolwell): Rename feature since it now affects more than just the
-  // site-per-process case.
-  if (base::FeatureList::IsEnabled(
-          features::kSitePerProcessOnlyForHighMemoryClients)) {
-    int memory_threshold_mb = base::GetFieldTrialParamByFeatureAsInt(
-        features::kSitePerProcessOnlyForHighMemoryClients,
-        features::kSitePerProcessOnlyForHighMemoryClientsParamName,
-        kDefaultMemoryThresholdMb);
-    return base::SysInfo::AmountOfPhysicalMemoryMB() <= memory_threshold_mb;
-  }
-
-#if defined(OS_ANDROID)
-  if (base::SysInfo::AmountOfPhysicalMemoryMB() <= kDefaultMemoryThresholdMb) {
-    return true;
-  }
-#endif
-
-  return false;
+  return SiteIsolationPolicy::ShouldDisableSiteIsolationDueToMemoryThreshold();
 }
 
 std::vector<std::string>
diff --git a/chrome/browser/chrome_content_browser_client_browsertest.cc b/chrome/browser/chrome_content_browser_client_browsertest.cc
index 374d6825..0f4cf5f5 100644
--- a/chrome/browser/chrome_content_browser_client_browsertest.cc
+++ b/chrome/browser/chrome_content_browser_client_browsertest.cc
@@ -14,6 +14,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
+#include "base/test/mock_entropy_provider.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
@@ -22,6 +23,7 @@
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/search.h"
+#include "chrome/browser/site_isolation/site_isolation_policy.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/search/instant_test_base.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -35,6 +37,7 @@
 #include "components/network_session_configurator/common/network_switches.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/prefs/pref_service.h"
+#include "components/variations/variations_switches.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
@@ -503,6 +506,322 @@
   }
 }
 
+// Helper class to run tests with password-triggered site isolation initialized
+// via a regular field trial and *not* via a command-line override.  It
+// creates a new field trial (with 100% probability of being in the group), and
+// initializes the test class's ScopedFeatureList using it.  Two derived
+// classes below control are used to initialize the feature to either enabled
+// or disabled state.
+class PasswordSiteIsolationFieldTrialTest
+    : public SitePerProcessMemoryThresholdBrowserTest {
+ public:
+  explicit PasswordSiteIsolationFieldTrialTest(bool should_enable)
+      : field_trial_list_(std::make_unique<base::MockEntropyProvider>()) {
+    const std::string kTrialName = "PasswordSiteIsolation";
+    const std::string kGroupName = "FooGroup";  // unused
+    scoped_refptr<base::FieldTrial> trial =
+        base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+
+    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+    feature_list->RegisterFieldTrialOverride(
+        features::kSiteIsolationForPasswordSites.name,
+        should_enable
+            ? base::FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE
+            : base::FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE,
+        trial.get());
+
+    feature_list_.InitWithFeatureList(std::move(feature_list));
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // This test creates and tests its own field trial group, so it needs to
+    // disable the field trial testing config, which might define an
+    // incompatible trial name/group.
+    command_line->AppendSwitch(
+        variations::switches::kDisableFieldTrialTestingConfig);
+    SitePerProcessMemoryThresholdBrowserTest::SetUpCommandLine(command_line);
+  }
+
+ protected:
+  base::test::ScopedFeatureList feature_list_;
+  base::FieldTrialList field_trial_list_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PasswordSiteIsolationFieldTrialTest);
+};
+
+class EnabledPasswordSiteIsolationFieldTrialTest
+    : public PasswordSiteIsolationFieldTrialTest {
+ public:
+  EnabledPasswordSiteIsolationFieldTrialTest()
+      : PasswordSiteIsolationFieldTrialTest(true /* should_enable */) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EnabledPasswordSiteIsolationFieldTrialTest);
+};
+
+class DisabledPasswordSiteIsolationFieldTrialTest
+    : public PasswordSiteIsolationFieldTrialTest {
+ public:
+  DisabledPasswordSiteIsolationFieldTrialTest()
+      : PasswordSiteIsolationFieldTrialTest(false /* should_enable */) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DisabledPasswordSiteIsolationFieldTrialTest);
+};
+
+IN_PROC_BROWSER_TEST_F(EnabledPasswordSiteIsolationFieldTrialTest,
+                       BelowThreshold) {
+  if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+    return;
+
+  // If no memory threshold is defined, password site isolation should be
+  // enabled.
+  EXPECT_TRUE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+  // Define a memory threshold at 768MB.  Since this is above the 512MB of
+  // physical memory that this test simulates, password site isolation should
+  // now be disabled.
+  base::test::ScopedFeatureList memory_feature;
+  memory_feature.InitAndEnableFeatureWithParameters(
+      features::kSitePerProcessOnlyForHighMemoryClients,
+      {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}});
+
+  EXPECT_FALSE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+  // Simulate enabling password site isolation from command line.  (Note that
+  // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine
+  // internally, and that triggering the feature via chrome://flags follows the
+  // same override path as well.)
+  base::test::ScopedFeatureList password_site_isolation_feature;
+  password_site_isolation_feature.InitAndEnableFeature(
+      features::kSiteIsolationForPasswordSites);
+
+  // This should override the memory threshold and enable password site
+  // isolation.
+  EXPECT_TRUE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+}
+
+IN_PROC_BROWSER_TEST_F(EnabledPasswordSiteIsolationFieldTrialTest,
+                       AboveThreshold) {
+  if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+    return;
+
+  // If no memory threshold is defined, password site isolation should be
+  // enabled.
+  EXPECT_TRUE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+  // Define a memory threshold at 128MB.  Since this is below the 512MB of
+  // physical memory that this test simulates, password site isolation should
+  // still be enabled.
+  base::test::ScopedFeatureList memory_feature;
+  memory_feature.InitAndEnableFeatureWithParameters(
+      features::kSitePerProcessOnlyForHighMemoryClients,
+      {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}});
+
+  EXPECT_TRUE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+  // Simulate disabling password site isolation from command line.  (Note that
+  // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine
+  // internally, and that triggering the feature via chrome://flags follows the
+  // same override path as well.)  This should take precedence over the regular
+  // field trial behavior.
+  base::test::ScopedFeatureList password_site_isolation_feature;
+  password_site_isolation_feature.InitAndDisableFeature(
+      features::kSiteIsolationForPasswordSites);
+  EXPECT_FALSE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+}
+
+// This test verifies that when password-triggered site isolation is disabled
+// via field trials but force-enabled via command line, it takes effect even
+// when below the memory threshold.  See https://crbug.com/1009828.
+IN_PROC_BROWSER_TEST_F(DisabledPasswordSiteIsolationFieldTrialTest,
+                       CommandLineOverride_BelowThreshold) {
+  if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+    return;
+
+  // Password site isolation should be disabled at this point.
+  EXPECT_FALSE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+  // Simulate enabling password site isolation from command line.  (Note that
+  // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine
+  // internally, and that triggering the feature via chrome://flags follows the
+  // same override path as well.)
+  base::test::ScopedFeatureList password_site_isolation_feature;
+  password_site_isolation_feature.InitAndEnableFeature(
+      features::kSiteIsolationForPasswordSites);
+
+  // If no memory threshold is defined, password site isolation should be
+  // enabled.
+  EXPECT_TRUE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+  // Define a memory threshold at 768MB.  This is above the 512MB of physical
+  // memory that this test simulates, but password site isolation should still
+  // be enabled, because the test has simulated the user manually overriding
+  // this feature via command line.
+  base::test::ScopedFeatureList memory_feature;
+  memory_feature.InitAndEnableFeatureWithParameters(
+      features::kSitePerProcessOnlyForHighMemoryClients,
+      {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}});
+
+  EXPECT_TRUE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+}
+
+// Similar to the test above, but with device memory being above memory
+// threshold.
+IN_PROC_BROWSER_TEST_F(DisabledPasswordSiteIsolationFieldTrialTest,
+                       CommandLineOverride_AboveThreshold) {
+  if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+    return;
+
+  EXPECT_FALSE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+  base::test::ScopedFeatureList password_site_isolation_feature;
+  password_site_isolation_feature.InitAndEnableFeature(
+      features::kSiteIsolationForPasswordSites);
+
+  // If no memory threshold is defined, password site isolation should be
+  // enabled.
+  EXPECT_TRUE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+
+  base::test::ScopedFeatureList memory_feature;
+  memory_feature.InitAndEnableFeatureWithParameters(
+      features::kSitePerProcessOnlyForHighMemoryClients,
+      {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}});
+
+  EXPECT_TRUE(::SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
+}
+
+// Helper class to run tests with strict origin isolation initialized via
+// a regular field trial and *not* via a command-line override.  It creates a
+// new field trial (with 100% probability of being in the group), and
+// initializes the test class's ScopedFeatureList using it.  Two derived
+// classes below control are used to initialize the feature to either enabled
+// or disabled state.
+class StrictOriginIsolationFieldTrialTest
+    : public SitePerProcessMemoryThresholdBrowserTest {
+ public:
+  explicit StrictOriginIsolationFieldTrialTest(bool should_enable)
+      : field_trial_list_(std::make_unique<base::MockEntropyProvider>()) {
+    const std::string kTrialName = "StrictOriginIsolation";
+    const std::string kGroupName = "FooGroup";  // unused
+    scoped_refptr<base::FieldTrial> trial =
+        base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+
+    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+    feature_list->RegisterFieldTrialOverride(
+        features::kStrictOriginIsolation.name,
+        should_enable
+            ? base::FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE
+            : base::FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE,
+        trial.get());
+
+    feature_list_.InitWithFeatureList(std::move(feature_list));
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // This test creates and tests its own field trial group, so it needs to
+    // disable the field trial testing config, which might define an
+    // incompatible trial name/group.
+    command_line->AppendSwitch(
+        variations::switches::kDisableFieldTrialTestingConfig);
+    SitePerProcessMemoryThresholdBrowserTest::SetUpCommandLine(command_line);
+  }
+
+ protected:
+  base::test::ScopedFeatureList feature_list_;
+  base::FieldTrialList field_trial_list_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StrictOriginIsolationFieldTrialTest);
+};
+
+class EnabledStrictOriginIsolationFieldTrialTest
+    : public StrictOriginIsolationFieldTrialTest {
+ public:
+  EnabledStrictOriginIsolationFieldTrialTest()
+      : StrictOriginIsolationFieldTrialTest(true /* should_enable */) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EnabledStrictOriginIsolationFieldTrialTest);
+};
+
+class DisabledStrictOriginIsolationFieldTrialTest
+    : public StrictOriginIsolationFieldTrialTest {
+ public:
+  DisabledStrictOriginIsolationFieldTrialTest()
+      : StrictOriginIsolationFieldTrialTest(false /* should_enable */) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DisabledStrictOriginIsolationFieldTrialTest);
+};
+
+// Check that when strict origin isolation is enabled via a field trial, and
+// the device is above the memory threshold, disabling it via the command line
+// takes precedence.
+IN_PROC_BROWSER_TEST_F(EnabledStrictOriginIsolationFieldTrialTest,
+                       DisabledViaCommandLineOverride) {
+  if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+    return;
+
+  // If no memory threshold is defined, strict origin isolation should be
+  // enabled.
+  EXPECT_TRUE(SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+
+  // Define a memory threshold at 128MB.  Since this is below the 512MB of
+  // physical memory that this test simulates, strict origin isolation should
+  // still be enabled.
+  base::test::ScopedFeatureList memory_feature;
+  memory_feature.InitAndEnableFeatureWithParameters(
+      features::kSitePerProcessOnlyForHighMemoryClients,
+      {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}});
+  EXPECT_TRUE(SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+
+  // Simulate disabling strict origin isolation from command line.  (Note that
+  // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine
+  // internally, and that disabling the feature via chrome://flags follows the
+  // same override path as well.)
+  base::test::ScopedFeatureList strict_origin_isolation_feature;
+  strict_origin_isolation_feature.InitAndDisableFeature(
+      features::kStrictOriginIsolation);
+  EXPECT_FALSE(SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+}
+
+// This test verifies that when strict origin isolation is disabled
+// via field trials but force-enabled via command line, it takes effect even
+// when below the memory threshold.  See https://crbug.com/1009828.
+IN_PROC_BROWSER_TEST_F(DisabledStrictOriginIsolationFieldTrialTest,
+                       EnabledViaCommandLineOverride_BelowThreshold) {
+  if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+    return;
+
+  // Strict origin isolation should be disabled at this point.
+  EXPECT_FALSE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+
+  // Simulate enabling strict origin isolation from command line.  (Note that
+  // InitAndEnableFeature uses ScopedFeatureList::InitFromCommandLine
+  // internally, and that triggering the feature via chrome://flags follows the
+  // same override path as well.)
+  base::test::ScopedFeatureList strict_origin_isolation_feature;
+  strict_origin_isolation_feature.InitAndEnableFeature(
+      features::kStrictOriginIsolation);
+
+  // If no memory threshold is defined, strict origin isolation should be
+  // enabled.
+  EXPECT_TRUE(SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+
+  // Define a memory threshold at 768MB.  This is above the 512MB of physical
+  // memory that this test simulates, but strict origin isolation should still
+  // be enabled, because the test has simulated the user manually overriding
+  // this feature via command line.
+  base::test::ScopedFeatureList memory_feature;
+  memory_feature.InitAndEnableFeatureWithParameters(
+      features::kSitePerProcessOnlyForHighMemoryClients,
+      {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}});
+
+  EXPECT_TRUE(SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
+}
+
 // Helper class to test window creation from NTP.
 class OpenWindowFromNTPBrowserTest : public InProcessBrowserTest,
                                      public InstantTestBase {
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 0916a67..82289408 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -455,6 +455,8 @@
     "arc/arc_optin_uma.h",
     "arc/arc_support_host.cc",
     "arc/arc_support_host.h",
+    "arc/arc_ui_availability_reporter.cc",
+    "arc/arc_ui_availability_reporter.h",
     "arc/arc_util.cc",
     "arc/arc_util.h",
     "arc/arc_web_contents_data.cc",
@@ -2447,6 +2449,7 @@
     "arc/app_shortcuts/arc_app_shortcuts_request_unittest.cc",
     "arc/arc_migration_guide_notification_unittest.cc",
     "arc/arc_support_host_unittest.cc",
+    "arc/arc_ui_availability_reporter_unittest.cc",
     "arc/arc_util_unittest.cc",
     "arc/bluetooth/arc_bluetooth_bridge_unittest.cc",
     "arc/bluetooth/arc_bluetooth_task_queue_unittest.cc",
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
index 07c79f4d..48abea7 100644
--- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -832,6 +832,33 @@
                                  "Combo box * of *"));
 }
 
+IN_PROC_BROWSER_TEST_F(OobeSpokenFeedbackTest, ChromeVoxPanelTabsMenuEmpty) {
+  // The ChromeVox panel should not populate the tabs menu if we are in the
+  // OOBE.
+  ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled());
+  AccessibilityManager::Get()->EnableSpokenFeedback(true);
+  // Included to reduce flakiness.
+  while (speech_monitor_.GetNextUtterance() !=
+         "Press Search plus Space to activate.") {
+  }
+  // Press [search + .] to open ChromeVox Panel
+  ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+      nullptr, ui::VKEY_OEM_PERIOD, false, false, false, true));
+  while (speech_monitor_.GetNextUtterance() != "ChromeVox Panel") {
+  }
+  // Go to tabs menu and verify that it has no items.
+  ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+      nullptr, ui::VKEY_RIGHT, false, false, false, false));
+  while (speech_monitor_.GetNextUtterance() != "Speech") {
+  }
+  ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+      nullptr, ui::VKEY_RIGHT, false, false, false, false));
+  while (speech_monitor_.GetNextUtterance() != "Tabs") {
+  }
+  EXPECT_EQ("Menu", speech_monitor_.GetNextUtterance());
+  EXPECT_EQ("No items.", speech_monitor_.GetNextUtterance());
+}
+
 IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest,
                        MoveByCharacterPhoneticSpeechAndHints) {
   EnableChromeVox();
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
index 70c5d2d..4ac093b 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/chromeos/app_mode/startup_app_launcher_update_checker.h"
 #include "chrome/browser/chromeos/net/delay_network_call.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/install_tracker.h"
 #include "chrome/browser/extensions/install_tracker_factory.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
@@ -55,9 +54,7 @@
     : profile_(profile),
       app_id_(app_id),
       diagnostic_mode_(diagnostic_mode),
-      delegate_(delegate),
-      kiosk_app_manager_observer_(this),
-      install_observer_(this) {
+      delegate_(delegate) {
   DCHECK(profile_);
   DCHECK(crx_file::id_util::IdIsValid(app_id_));
   kiosk_app_manager_observer_.Add(KioskAppManager::Get());
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.h b/chrome/browser/chromeos/app_mode/startup_app_launcher.h
index f1a677f..dc97e52e 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.h
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.h
@@ -13,18 +13,15 @@
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
 #include "chrome/browser/extensions/install_observer.h"
+#include "chrome/browser/extensions/install_tracker.h"
 
 class Profile;
 
-namespace extensions {
-class InstallTracker;
-}
-
 namespace chromeos {
 
-class KioskAppManager;
 class StartupAppLauncherUpdateChecker;
 
 // Launches the app at startup. The flow roughly looks like this:
@@ -139,10 +136,10 @@
   std::unique_ptr<StartupAppLauncherUpdateChecker> update_checker_;
 
   ScopedObserver<KioskAppManager, KioskAppManagerObserver>
-      kiosk_app_manager_observer_;
+      kiosk_app_manager_observer_{this};
 
   ScopedObserver<extensions::InstallTracker, extensions::InstallObserver>
-      install_observer_;
+      install_observer_{this};
 
   base::WeakPtrFactory<StartupAppLauncher> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/chromeos/apps/apk_web_app_service.cc b/chrome/browser/chromeos/apps/apk_web_app_service.cc
index 7b59561b..44df8c81 100644
--- a/chrome/browser/chromeos/apps/apk_web_app_service.cc
+++ b/chrome/browser/chromeos/apps/apk_web_app_service.cc
@@ -21,7 +21,6 @@
 #include "components/arc/session/connection_holder.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/scoped_user_pref_update.h"
-#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/uninstall_reason.h"
 #include "extensions/common/extension.h"
@@ -70,9 +69,7 @@
 }
 
 ApkWebAppService::ApkWebAppService(Profile* profile)
-    : profile_(profile),
-      arc_app_list_prefs_(ArcAppListPrefs::Get(profile)),
-      observer_(this) {
+    : profile_(profile), arc_app_list_prefs_(ArcAppListPrefs::Get(profile)) {
   // Can be null in tests.
   if (arc_app_list_prefs_)
     arc_app_list_prefs_->AddObserver(this);
diff --git a/chrome/browser/chromeos/apps/apk_web_app_service.h b/chrome/browser/chromeos/apps/apk_web_app_service.h
index 695fa25..a74d869 100644
--- a/chrome/browser/chromeos/apps/apk_web_app_service.h
+++ b/chrome/browser/chromeos/apps/apk_web_app_service.h
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
 
 class ArcAppListPrefs;
@@ -96,7 +97,7 @@
 
   ScopedObserver<extensions::ExtensionRegistry,
                  extensions::ExtensionRegistryObserver>
-      observer_;
+      observer_{this};
 
   // Must go last.
   base::WeakPtrFactory<ApkWebAppService> weak_ptr_factory_{this};
diff --git a/chrome/browser/chromeos/arc/arc_optin_uma.cc b/chrome/browser/chromeos/arc/arc_optin_uma.cc
index 140506c..44656044 100644
--- a/chrome/browser/chromeos/arc/arc_optin_uma.cc
+++ b/chrome/browser/chromeos/arc/arc_optin_uma.cc
@@ -119,8 +119,24 @@
       base::TimeDelta::FromMinutes(10), 50);
 }
 
-void UpdatePlayStoreShowTime(const base::TimeDelta& elapsed_time,
-                             const Profile* profile) {
+void UpdateArcUiAvailableTime(const base::TimeDelta& elapsed_time,
+                              const std::string& mode,
+                              const Profile* profile) {
+  base::UmaHistogramCustomTimes(
+      GetHistogramNameByUserType("Arc.UiAvailable." + mode + ".TimeDelta",
+                                 profile),
+      elapsed_time, base::TimeDelta::FromSeconds(1),
+      base::TimeDelta::FromMinutes(5), 50);
+}
+
+void UpdatePlayStoreLaunchTime(const base::TimeDelta& elapsed_time) {
+  base::UmaHistogramCustomTimes("Arc.PlayStoreLaunch.TimeDelta", elapsed_time,
+                                base::TimeDelta::FromMilliseconds(10),
+                                base::TimeDelta::FromSeconds(20), 50);
+}
+
+void UpdatePlayStoreShownTimeDeprecated(const base::TimeDelta& elapsed_time,
+                                        const Profile* profile) {
   base::UmaHistogramCustomTimes(
       GetHistogramNameByUserType("Arc.PlayStoreShown.TimeDelta", profile),
       elapsed_time, base::TimeDelta::FromSeconds(1),
diff --git a/chrome/browser/chromeos/arc/arc_optin_uma.h b/chrome/browser/chromeos/arc/arc_optin_uma.h
index 991e32ea..bf0a02f 100644
--- a/chrome/browser/chromeos/arc/arc_optin_uma.h
+++ b/chrome/browser/chromeos/arc/arc_optin_uma.h
@@ -238,8 +238,14 @@
                                        const Profile* profile);
 void UpdatePlayAutoInstallRequestTime(const base::TimeDelta& elapsed_time,
                                       const Profile* profile);
-void UpdatePlayStoreShowTime(const base::TimeDelta& elapsed_time,
-                             const Profile* profile);
+void UpdateArcUiAvailableTime(const base::TimeDelta& elapsed_time,
+                              const std::string& mode,
+                              const Profile* profile);
+void UpdatePlayStoreLaunchTime(const base::TimeDelta& elapsed_time);
+// TODO(khmel): Remove this in favor of UpdateArcUiAvailableTime once it is
+// rolled and has confirmed usability.
+void UpdatePlayStoreShownTimeDeprecated(const base::TimeDelta& elapsed_time,
+                                        const Profile* profile);
 void UpdateSilentAuthCodeUMA(OptInSilentAuthCode state);
 void UpdateSupervisionTransitionResultUMA(
     mojom::SupervisionChangeStatus result);
diff --git a/chrome/browser/chromeos/arc/arc_ui_availability_reporter.cc b/chrome/browser/chromeos/arc/arc_ui_availability_reporter.cc
new file mode 100644
index 0000000..adb52f07
--- /dev/null
+++ b/chrome/browser/chromeos/arc/arc_ui_availability_reporter.cc
@@ -0,0 +1,126 @@
+// 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/chromeos/arc/arc_ui_availability_reporter.h"
+
+#include "chrome/browser/chromeos/arc/arc_optin_uma.h"
+#include "components/arc/arc_service_manager.h"
+#include "components/arc/session/arc_bridge_service.h"
+
+namespace arc {
+
+class ArcUiAvailabilityReporter::ConnectionNotifierBase {
+ public:
+  virtual ~ConnectionNotifierBase() = default;
+
+  // Returns true if connection is ready.
+  virtual bool IsConnected() = 0;
+
+ protected:
+  explicit ConnectionNotifierBase(ArcUiAvailabilityReporter* owner)
+      : owner_(owner) {}
+
+  ArcUiAvailabilityReporter* owner() { return owner_; }
+
+ private:
+  ArcUiAvailabilityReporter* const owner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConnectionNotifierBase);
+};
+
+namespace {
+
+template <typename InstanceType, typename HostType>
+class ConnectionNotifier
+    : public ArcUiAvailabilityReporter::ConnectionNotifierBase,
+      public ConnectionObserver<InstanceType> {
+ public:
+  // |owner_| owns this object and |ConnectionNotifier| is destroyed in case
+  // statistics is reported or ARC session is terminated on user log-out and
+  // this automatically destroys this object at time of destroying |owner_|.
+  // |holder_| is owned by ArcBridgeService this lives longer than
+  // |ArcUiAvailabilityReporter|.
+  ConnectionNotifier(ArcUiAvailabilityReporter* owner,
+                     ConnectionHolder<InstanceType, HostType>* holder)
+      : ArcUiAvailabilityReporter::ConnectionNotifierBase(owner),
+        holder_(holder) {
+    DCHECK(!holder_->IsConnected());
+    holder_->AddObserver(this);
+  }
+
+  ~ConnectionNotifier() override { holder_->RemoveObserver(this); }
+
+  // ArcUiAvailabilityReporter::ConnectionNotifierBase:
+  bool IsConnected() override { return holder_->IsConnected(); }
+
+  // ConnectionObserver<InstanceType>:
+  void OnConnectionReady() override { owner()->MaybeReport(); }
+
+ private:
+  ConnectionHolder<InstanceType, HostType>* const holder_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConnectionNotifier);
+};
+
+}  // namespace
+
+ArcUiAvailabilityReporter::ArcUiAvailabilityReporter(Profile* profile,
+                                                     Mode mode)
+    : profile_(profile), mode_(mode), start_ticks_(base::TimeTicks::Now()) {
+  DCHECK(profile);
+  // Some unit tests may not have |ArcServiceManager| set.
+  ArcServiceManager* const service_manager = ArcServiceManager::Get();
+  if (!service_manager)
+    return;
+  // |initiated_from_oobe| must be set only if |initial_start| is set.
+  auto* const arc_bridge = ArcServiceManager::Get()->arc_bridge_service();
+  // Not expected instances are connected at the time of creation, however this
+  // is not always preserved in tests.
+  if (arc_bridge->app()->IsConnected() ||
+      arc_bridge->intent_helper()->IsConnected()) {
+    LOG(ERROR) << "App and/or intent_helper instances are already connected. "
+               << "This is not expected in production.";
+    return;
+  }
+
+  connection_notifiers_.emplace_back(
+      std::make_unique<ConnectionNotifier<mojom::AppInstance, mojom::AppHost>>(
+          this, arc_bridge->app()));
+  connection_notifiers_.emplace_back(
+      std::make_unique<ConnectionNotifier<mojom::IntentHelperInstance,
+                                          mojom::IntentHelperHost>>(
+          this, arc_bridge->intent_helper()));
+}
+
+ArcUiAvailabilityReporter::~ArcUiAvailabilityReporter() = default;
+
+// static
+std::string ArcUiAvailabilityReporter::GetHistogramNameForMode(Mode mode) {
+  switch (mode) {
+    case Mode::kOobeProvisioning:
+      return "OobeProvisioning";
+    case Mode::kInSessionProvisioning:
+      return "InSessionProvisioning";
+    case Mode::kAlreadyProvisioned:
+      return "AlreadyProvisioned";
+  }
+}
+
+void ArcUiAvailabilityReporter::MaybeReport() {
+  DCHECK(!connection_notifiers_.empty());
+
+  // Check that all tracked instance are connected.
+  for (const auto& connection_notifier : connection_notifiers_) {
+    if (!connection_notifier->IsConnected())
+      return;
+  }
+
+  UpdateArcUiAvailableTime(base::TimeTicks::Now() - start_ticks_,
+                           GetHistogramNameForMode(mode_), profile_);
+
+  // No more reporting is expected.
+  connection_notifiers_.clear();
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/arc_ui_availability_reporter.h b/chrome/browser/chromeos/arc/arc_ui_availability_reporter.h
new file mode 100644
index 0000000..f5d73ea3
--- /dev/null
+++ b/chrome/browser/chromeos/arc/arc_ui_availability_reporter.h
@@ -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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ARC_ARC_UI_AVAILABILITY_REPORTER_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_ARC_UI_AVAILABILITY_REPORTER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+
+class Profile;
+
+namespace arc {
+
+// Helper class that reports ARC UI availability to UMA. It observes major UI
+// instances are all connected.
+class ArcUiAvailabilityReporter {
+ public:
+  // Helper that notifies |ArcUiAvailabilityReporter| that connection is ready.
+  class ConnectionNotifierBase;
+
+  enum class Mode {
+    kOobeProvisioning,
+    kInSessionProvisioning,
+    kAlreadyProvisioned
+  };
+
+  ArcUiAvailabilityReporter(Profile* profile, Mode mode);
+  ~ArcUiAvailabilityReporter();
+
+  static std::string GetHistogramNameForMode(Mode mode);
+
+  // Called when any tracked instance is connected.
+  void MaybeReport();
+
+ private:
+  Profile* const profile_;
+  const Mode mode_;
+  const base::TimeTicks start_ticks_;
+
+  std::vector<std::unique_ptr<ConnectionNotifierBase>> connection_notifiers_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcUiAvailabilityReporter);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_ARC_UI_AVAILABILITY_REPORTER_H_
diff --git a/chrome/browser/chromeos/arc/arc_ui_availability_reporter_unittest.cc b/chrome/browser/chromeos/arc/arc_ui_availability_reporter_unittest.cc
new file mode 100644
index 0000000..60e3571
--- /dev/null
+++ b/chrome/browser/chromeos/arc/arc_ui_availability_reporter_unittest.cc
@@ -0,0 +1,139 @@
+// 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/chromeos/arc/arc_ui_availability_reporter.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_test.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/arc/arc_service_manager.h"
+#include "components/arc/arc_util.h"
+#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
+#include "components/arc/session/arc_bridge_service.h"
+#include "components/arc/test/fake_app_instance.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace arc {
+
+namespace {
+
+using Mode = ArcUiAvailabilityReporter::Mode;
+
+const base::HistogramBase* GetHistogram(Mode mode) {
+  return base::StatisticsRecorder::FindHistogram(
+      "Arc.UiAvailable." +
+      ArcUiAvailabilityReporter::GetHistogramNameForMode(mode) +
+      ".TimeDelta.Unmanaged");
+}
+
+int64_t ReadSingleStatistics(Mode mode) {
+  const base::HistogramBase* histogram = GetHistogram(mode);
+  DCHECK(histogram);
+
+  std::unique_ptr<base::HistogramSamples> samples =
+      histogram->SnapshotFinalDelta();
+  DCHECK(samples.get());
+  // Expected reported only once.
+  DCHECK_EQ(1, samples->TotalCount());
+  return samples->sum();
+}
+
+}  // namespace
+
+class ArcUiAvailabilityReporterTest : public testing::Test {
+ public:
+  ArcUiAvailabilityReporterTest() {}
+  ~ArcUiAvailabilityReporterTest() override = default;
+
+  void SetUp() override {
+    testing::Test::SetUp();
+    arc::SetArcAvailableCommandLineForTesting(
+        base::CommandLine::ForCurrentProcess());
+    // arc_service_manager_ = std::make_unique<arc::ArcServiceManager>();
+    profile_ = TestingProfile::Builder().Build();
+
+    // Use ArcAppTest to initialize infrastructure.
+    arc_app_test_.set_activate_arc_on_start(false);
+    arc_app_test_.SetUp(profile());
+    app_instance_ = std::make_unique<FakeAppInstance>(
+        arc_app_test_.arc_app_list_prefs() /* app_host */);
+    intent_helper_instance_ = std::make_unique<FakeIntentHelperInstance>();
+    arc_intent_helper_bridge_ = std::make_unique<ArcIntentHelperBridge>(
+        profile(), arc_bridge_service());
+  }
+
+  void TearDown() override {
+    arc_intent_helper_bridge_.reset();
+    intent_helper_instance_.reset();
+    app_instance_.reset();
+    arc_app_test_.TearDown();
+    profile_.reset();
+    // arc_service_manager_.reset();
+    testing::Test::TearDown();
+  }
+
+  TestingProfile* profile() { return profile_.get(); }
+
+  ArcBridgeService* arc_bridge_service() {
+    return ArcServiceManager::Get()->arc_bridge_service();
+  }
+
+  FakeAppInstance* app_instance() { return app_instance_.get(); }
+
+  FakeIntentHelperInstance* intent_helper_instance() {
+    return intent_helper_instance_.get();
+  }
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+  // std::unique_ptr<arc::ArcServiceManager> arc_service_manager_;
+  std::unique_ptr<TestingProfile> profile_;
+  ArcAppTest arc_app_test_;
+  std::unique_ptr<ArcIntentHelperBridge> arc_intent_helper_bridge_;
+  std::unique_ptr<FakeAppInstance> app_instance_;
+  std::unique_ptr<FakeIntentHelperInstance> intent_helper_instance_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcUiAvailabilityReporterTest);
+};
+
+// Reporting is triggered in case both instances are connected.
+TEST_F(ArcUiAvailabilityReporterTest, Basic) {
+  ArcUiAvailabilityReporter reporter(profile(), Mode::kOobeProvisioning);
+  // No reporting at this time.
+  EXPECT_FALSE(GetHistogram(Mode::kOobeProvisioning));
+  arc_bridge_service()->app()->SetInstance(app_instance());
+  EXPECT_FALSE(GetHistogram(Mode::kOobeProvisioning));
+  arc_bridge_service()->intent_helper()->SetInstance(intent_helper_instance());
+  EXPECT_GE(ReadSingleStatistics(Mode::kOobeProvisioning), 0);
+  EXPECT_FALSE(GetHistogram(Mode::kInSessionProvisioning));
+  EXPECT_FALSE(GetHistogram(Mode::kAlreadyProvisioned));
+}
+
+// Reporting is triggered only once, even if instances are reconnected.
+TEST_F(ArcUiAvailabilityReporterTest, TriggeredOnce) {
+  ArcUiAvailabilityReporter reporter(profile(), Mode::kAlreadyProvisioned);
+  arc_bridge_service()->app()->SetInstance(app_instance());
+  arc_bridge_service()->intent_helper()->SetInstance(intent_helper_instance());
+  arc_bridge_service()->app()->CloseInstance(app_instance());
+  arc_bridge_service()->intent_helper()->CloseInstance(
+      intent_helper_instance());
+  arc_bridge_service()->app()->SetInstance(app_instance());
+  arc_bridge_service()->intent_helper()->SetInstance(intent_helper_instance());
+  EXPECT_GE(ReadSingleStatistics(Mode::kAlreadyProvisioned), 0);
+}
+
+// Reporting is triggered even if instance restart happened.
+TEST_F(ArcUiAvailabilityReporterTest, InstanceRestartAllowed) {
+  ArcUiAvailabilityReporter reporter(profile(), Mode::kInSessionProvisioning);
+  arc_bridge_service()->app()->SetInstance(app_instance());
+  arc_bridge_service()->app()->CloseInstance(app_instance());
+  arc_bridge_service()->intent_helper()->SetInstance(intent_helper_instance());
+  arc_bridge_service()->app()->SetInstance(app_instance());
+  EXPECT_GE(ReadSingleStatistics(Mode::kInSessionProvisioning), 0);
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager.cc b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
index 2742271..265a9a8 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/chromeos/arc/arc_migration_guide_notification.h"
 #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
+#include "chrome/browser/chromeos/arc/arc_ui_availability_reporter.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
 #include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator.h"
@@ -520,6 +521,7 @@
   }
   pai_starter_.reset();
   fast_app_reinstall_starter_.reset();
+  arc_ui_availability_reporter_.reset();
   profile_ = nullptr;
   state_ = State::NOT_INITIALIZED;
   if (scoped_opt_in_tracker_) {
@@ -679,7 +681,9 @@
   // the initial request.
   // |prefs::kArcProvisioningInitiatedFromOobe| is reset when provisioning is
   // done or ARC is opted out.
-  if (IsArcOobeOptInActive())
+  const bool opt_in_start = IsArcOobeOptInActive();
+  const bool signed_in = prefs->GetBoolean(prefs::kArcSignedIn);
+  if (opt_in_start)
     prefs->SetBoolean(prefs::kArcProvisioningInitiatedFromOobe, true);
 
   // If it is marked that sign in has been successfully done or if Play Store is
@@ -689,9 +693,9 @@
   // In Public Session mode ARC should be started silently without user
   // interaction. If opt-in verification is disabled, skip negotiation, too.
   // This is for testing purpose.
-  const bool start_arc_directly =
-      prefs->GetBoolean(prefs::kArcSignedIn) || ShouldArcAlwaysStart() ||
-      IsRobotOrOfflineDemoAccountMode() || IsArcOptInVerificationDisabled();
+  const bool start_arc_directly = signed_in || ShouldArcAlwaysStart() ||
+                                  IsRobotOrOfflineDemoAccountMode() ||
+                                  IsArcOptInVerificationDisabled();
 
   // When ARC is blocked because of filesystem compatibility, do not proceed
   // to starting ARC nor follow further state transitions.
@@ -703,6 +707,18 @@
     return false;
   }
 
+  // ARC might be re-enabled and in this case |arc_ui_availability_reporter_| is
+  // already set.
+  if (!arc_ui_availability_reporter_) {
+    arc_ui_availability_reporter_ = std::make_unique<ArcUiAvailabilityReporter>(
+        profile_,
+        opt_in_start
+            ? ArcUiAvailabilityReporter::Mode::kOobeProvisioning
+            : signed_in
+                  ? ArcUiAvailabilityReporter::Mode::kAlreadyProvisioned
+                  : ArcUiAvailabilityReporter::Mode::kInSessionProvisioning);
+  }
+
   if (!pai_starter_ && IsPlayStoreAvailable())
     pai_starter_ = ArcPaiStarter::CreateIfNeeded(profile_);
 
@@ -752,6 +768,7 @@
   scoped_opt_in_tracker_.reset();
   pai_starter_.reset();
   fast_app_reinstall_starter_.reset();
+  arc_ui_availability_reporter_.reset();
 
   // Reset any pending request to re-enable ARC.
   reenable_arc_ = false;
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager.h b/chrome/browser/chromeos/arc/session/arc_session_manager.h
index 5ad9eb0..4bd1accb 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager.h
@@ -29,6 +29,8 @@
 class ArcFastAppReinstallStarter;
 class ArcPaiStarter;
 class ArcTermsOfServiceNegotiator;
+class ArcUiAvailabilityReporter;
+
 enum class ProvisioningResult : int;
 
 // This class is responsible for handing stages of ARC life-cycle.
@@ -375,6 +377,7 @@
   std::unique_ptr<ScopedOptInFlowTracker> scoped_opt_in_tracker_;
   std::unique_ptr<ArcPaiStarter> pai_starter_;
   std::unique_ptr<ArcFastAppReinstallStarter> fast_app_reinstall_starter_;
+  std::unique_ptr<ArcUiAvailabilityReporter> arc_ui_availability_reporter_;
 
   // The time when the sign in process started.
   base::TimeTicks sign_in_start_time_;
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.h b/chrome/browser/chromeos/drive/drive_integration_service.h
index 45aa4cd..760850fe 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.h
+++ b/chrome/browser/chromeos/drive/drive_integration_service.h
@@ -305,8 +305,9 @@
 
   base::TimeTicks mount_start_;
 
-  ScopedObserver<chromeos::PowerManagerClient, DriveIntegrationService>
-      power_manager_observer_;
+  ScopedObserver<chromeos::PowerManagerClient,
+                 chromeos::PowerManagerClient::Observer>
+      power_manager_observer_{this};
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.cc b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.cc
index e3ea0413..4e07e07 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.cc
@@ -15,7 +15,6 @@
 #include "chromeos/tpm/install_attributes.h"
 #include "components/session_manager/core/session_manager.h"
 #include "content/public/browser/browser_thread.h"
-#include "extensions/browser/extension_registry.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/permissions/permissions_data.h"
@@ -94,9 +93,7 @@
 
 LoginScreenExtensionUiHandler::LoginScreenExtensionUiHandler(
     std::unique_ptr<LoginScreenExtensionUiWindowFactory> window_factory)
-    : window_factory_(std::move(window_factory)),
-      session_manager_observer_(this),
-      extension_registry_observer_(this) {
+    : window_factory_(std::move(window_factory)) {
   UpdateSessionState();
   session_manager_observer_.Add(session_manager::SessionManager::Get());
   extension_registry_observer_.Add(
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.h b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.h
index e847f1f..89929da1 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.h
+++ b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_extension_ui_handler.h
@@ -10,18 +10,15 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
+#include "components/session_manager/core/session_manager.h"
 #include "components/session_manager/core/session_manager_observer.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
 
 namespace extensions {
 class Extension;
-class ExtensionRegistry;
 }  // namespace extensions
 
-namespace session_manager {
-class SessionManager;
-}
-
 namespace chromeos {
 
 class LoginScreenExtensionUiWindow;
@@ -95,10 +92,10 @@
 
   ScopedObserver<session_manager::SessionManager,
                  session_manager::SessionManagerObserver>
-      session_manager_observer_;
+      session_manager_observer_{this};
   ScopedObserver<extensions::ExtensionRegistry,
                  extensions::ExtensionRegistryObserver>
-      extension_registry_observer_;
+      extension_registry_observer_{this};
 
   base::WeakPtrFactory<LoginScreenExtensionUiHandler> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
index 32933c4..fc9edbc61 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -191,6 +191,10 @@
   RunTestURL("foreground/js/ui/file_list_selection_model_unittest_gen.html");
 }
 
+IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileManagerDialogBaseTest) {
+  RunTestURL("foreground/js/ui/file_manager_dialog_base_unittest_gen.html");
+}
+
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, MultiMenu) {
   RunTestURL("foreground/js/ui/multi_menu_unittest_gen.html");
 }
diff --git a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
index 7dc8a04..a03c0d8 100644
--- a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
+++ b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
@@ -419,7 +419,7 @@
   observers_.AddObserver(observer);
 }
 
-void KerberosCredentialsManager::RemoveObserver(const Observer* observer) {
+void KerberosCredentialsManager::RemoveObserver(Observer* observer) {
   observers_.RemoveObserver(observer);
 }
 
diff --git a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h
index 0e19b8f..2869727 100644
--- a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h
+++ b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h
@@ -88,7 +88,7 @@
   void AddObserver(Observer* observer);
 
   // Stop observing this object. |observer| is not owned.
-  void RemoveObserver(const Observer* observer);
+  void RemoveObserver(Observer* observer);
 
   // Adds an account for the given |principal_name| (user@example.com). If
   // |is_managed| is true, the account is assumed to be managed by an admin and
diff --git a/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.cc b/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.cc
index 26381b8..294b2c6 100644
--- a/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.cc
@@ -19,7 +19,6 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/views/widget/widget.h"
 
 namespace lock_screen_apps {
 
@@ -63,9 +62,7 @@
 };
 
 FirstAppRunToastManager::FirstAppRunToastManager(Profile* profile)
-    : profile_(profile),
-      toast_widget_observer_(this),
-      app_window_observer_(this) {}
+    : profile_(profile) {}
 
 FirstAppRunToastManager::~FirstAppRunToastManager() {
   Reset();
diff --git a/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.h b/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.h
index 4e7ec86c..7910e77 100644
--- a/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.h
+++ b/chrome/browser/chromeos/lock_screen_apps/first_app_run_toast_manager.h
@@ -9,15 +9,11 @@
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "extensions/browser/app_window/app_window_registry.h"
-#include "ui/aura/window_observer.h"
+#include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_observer.h"
 
 class Profile;
 
-namespace views {
-class Widget;
-}
-
 namespace extensions {
 class AppWindow;
 }
@@ -77,10 +73,11 @@
   // The widget associated with the first run dialog, if the dialog is shown.
   views::Widget* toast_widget_ = nullptr;
 
-  ScopedObserver<views::Widget, views::WidgetObserver> toast_widget_observer_;
+  ScopedObserver<views::Widget, views::WidgetObserver> toast_widget_observer_{
+      this};
   ScopedObserver<extensions::AppWindowRegistry,
                  extensions::AppWindowRegistry::Observer>
-      app_window_observer_;
+      app_window_observer_{this};
 
   class AppWidgetObserver;
   std::unique_ptr<AppWidgetObserver> app_widget_observer_;
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
index ce6bfc2..7957a4de 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
@@ -29,7 +29,6 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
-#include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user.h"
 #include "content/public/browser/system_connector.h"
 #include "content/public/browser/web_contents.h"
@@ -39,7 +38,6 @@
 #include "extensions/browser/app_window/native_app_window.h"
 #include "extensions/common/extension.h"
 #include "services/service_manager/public/cpp/connector.h"
-#include "ui/events/devices/device_data_manager.h"
 #include "ui/wm/core/window_animations.h"
 
 using ash::mojom::CloseLockScreenNoteReason;
@@ -78,13 +76,7 @@
   registry->RegisterStringPref(kDataCryptoKeyPref, "");
 }
 
-StateController::StateController()
-    : binding_(this),
-      note_window_observer_(this),
-      app_window_observer_(this),
-      session_observer_(this),
-      input_devices_observer_(this),
-      power_manager_client_observer_(this) {
+StateController::StateController() {
   DCHECK(!g_state_controller_instance);
 
   g_state_controller_instance = this;
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.h b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
index 3771f3d3..1fef6ce 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.h
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
@@ -17,20 +17,18 @@
 #include "chrome/browser/chromeos/lock_screen_apps/app_manager.h"
 #include "chrome/browser/chromeos/lock_screen_apps/state_observer.h"
 #include "chromeos/dbus/power/power_manager_client.h"
+#include "components/session_manager/core/session_manager.h"
 #include "components/session_manager/core/session_manager_observer.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/common/api/app_runtime.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "ui/aura/window.h"
+#include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/input_device_event_observer.h"
 
 class PrefRegistrySimple;
 class Profile;
 
-namespace aura {
-class Window;
-}
-
 namespace base {
 class TickClock;
 }
@@ -49,14 +47,6 @@
 }
 }  // namespace extensions
 
-namespace session_manager {
-class SessionManager;
-}
-
-namespace ui {
-class DeviceDataManager;
-}
-
 namespace lock_screen_apps {
 
 class AppWindowMetricsTracker;
@@ -220,7 +210,7 @@
 
   base::ObserverList<StateObserver>::Unchecked observers_;
 
-  mojo::Binding<ash::mojom::TrayActionClient> binding_;
+  mojo::Binding<ash::mojom::TrayActionClient> binding_{this};
   ash::mojom::TrayActionPtr tray_action_ptr_;
 
   std::unique_ptr<LockScreenProfileCreator> lock_screen_profile_creator_;
@@ -251,18 +241,19 @@
   // for the associated app has been previosly seen (and closed) by the user.
   std::unique_ptr<FirstAppRunToastManager> first_app_run_toast_manager_;
 
-  ScopedObserver<aura::Window, aura::WindowObserver> note_window_observer_;
+  ScopedObserver<aura::Window, aura::WindowObserver> note_window_observer_{
+      this};
   ScopedObserver<extensions::AppWindowRegistry,
                  extensions::AppWindowRegistry::Observer>
-      app_window_observer_;
+      app_window_observer_{this};
   ScopedObserver<session_manager::SessionManager,
                  session_manager::SessionManagerObserver>
-      session_observer_;
+      session_observer_{this};
   ScopedObserver<ui::DeviceDataManager, ui::InputDeviceEventObserver>
-      input_devices_observer_;
+      input_devices_observer_{this};
   ScopedObserver<chromeos::PowerManagerClient,
                  chromeos::PowerManagerClient::Observer>
-      power_manager_client_observer_;
+      power_manager_client_observer_{this};
 
   // If set, this callback will be run when the state controller is fully
   // initialized. It can be used to throttle tests until state controller
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_mode_resources_remover.cc b/chrome/browser/chromeos/login/demo_mode/demo_mode_resources_remover.cc
index 4b7d6df..76181a8 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_mode_resources_remover.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_mode_resources_remover.cc
@@ -33,7 +33,6 @@
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_type.h"
 #include "third_party/re2/src/re2/re2.h"
-#include "ui/base/user_activity/user_activity_detector.h"
 
 namespace chromeos {
 
@@ -250,9 +249,7 @@
 
 DemoModeResourcesRemover::DemoModeResourcesRemover(PrefService* local_state)
     : local_state_(local_state),
-      tick_clock_(base::DefaultTickClock::GetInstance()),
-      cryptohome_observer_(this),
-      user_activity_observer_(this) {
+      tick_clock_(base::DefaultTickClock::GetInstance()) {
   CHECK(!g_instance);
   g_instance = this;
 
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_mode_resources_remover.h b/chrome/browser/chromeos/login/demo_mode/demo_mode_resources_remover.h
index a43214cd..ce8b366 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_mode_resources_remover.h
+++ b/chrome/browser/chromeos/login/demo_mode/demo_mode_resources_remover.h
@@ -16,6 +16,7 @@
 #include "base/scoped_observer.h"
 #include "chromeos/dbus/cryptohome/cryptohome_client.h"
 #include "components/user_manager/user_manager.h"
+#include "ui/base/user_activity/user_activity_detector.h"
 #include "ui/base/user_activity/user_activity_observer.h"
 
 class PrefRegistrySimple;
@@ -29,7 +30,6 @@
 
 namespace ui {
 class Event;
-class UserActivityDetector;
 }  // namespace ui
 
 namespace chromeos {
@@ -189,10 +189,10 @@
   base::Optional<base::TimeTicks> usage_start_;
   base::Optional<base::TimeTicks> usage_end_;
 
-  ScopedObserver<CryptohomeClient, DemoModeResourcesRemover>
-      cryptohome_observer_;
-  ScopedObserver<ui::UserActivityDetector, DemoModeResourcesRemover>
-      user_activity_observer_;
+  ScopedObserver<CryptohomeClient, CryptohomeClient::Observer>
+      cryptohome_observer_{this};
+  ScopedObserver<ui::UserActivityDetector, ui::UserActivityObserver>
+      user_activity_observer_{this};
 
   base::WeakPtrFactory<DemoModeResourcesRemover> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session.cc b/chrome/browser/chromeos/login/demo_mode/demo_session.cc
index 609ddf5..395f6af 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_session.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_session.cc
@@ -41,12 +41,10 @@
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
-#include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/network_service_instance.h"
 #include "extensions/browser/app_window/app_window.h"
-#include "extensions/browser/extension_registry.h"
 #include "extensions/common/constants.h"
 #include "services/network/public/cpp/network_connection_tracker.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session.h b/chrome/browser/chromeos/login/demo_mode/demo_session.h
index 1a2750b5..dc11ea3 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_session.h
+++ b/chrome/browser/chromeos/login/demo_mode/demo_session.h
@@ -15,9 +15,11 @@
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_extensions_external_loader.h"
+#include "components/session_manager/core/session_manager.h"
 #include "components/session_manager/core/session_manager_observer.h"
 #include "components/user_manager/user_manager.h"
 #include "extensions/browser/app_window/app_window_registry.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
 
 class PrefRegistrySimple;
@@ -26,10 +28,6 @@
 class OneShotTimer;
 }
 
-namespace session_manager {
-class SessionManager;
-}
-
 namespace chromeos {
 
 class DemoResources;
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 5eeeb93..edf6da32 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -354,7 +354,7 @@
 
  private:
   base::OnceClosure callback_;
-  ScopedObserver<policy::CloudPolicyStore, PolicyStoreLoadWaiter>
+  ScopedObserver<policy::CloudPolicyStore, policy::CloudPolicyStore::Observer>
       scoped_observer_{this};
 };
 
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.h b/chrome/browser/chromeos/login/lock/views_screen_locker.h
index e5e015e..ea5729a 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.h
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.h
@@ -123,7 +123,8 @@
   // up to a specific timeout.
   base::OneShotTimer external_binary_timer_;
 
-  ScopedObserver<chromeos::MediaAnalyticsClient, ViewsScreenLocker>
+  ScopedObserver<chromeos::MediaAnalyticsClient,
+                 chromeos::MediaAnalyticsClient::Observer>
       scoped_observer_{this};
 
   base::WeakPtrFactory<ViewsScreenLocker> weak_factory_{this};
diff --git a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
index bbdeb7a..0c00a70e 100644
--- a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
@@ -185,9 +185,7 @@
   test::OobeJS()
       .CreateEnabledWaiter(true, {"arc-tos-root", "arc-tos-next-button"})
       ->Wait();
-  test::OobeJS().Evaluate(
-      test::GetOobeElementPath({"arc-tos-root", "arc-tos-next-button"}) +
-      ".click()");
+  test::OobeJS().TapOnPath({"arc-tos-root", "arc-tos-next-button"});
   test::OobeJS()
       .CreateVisibilityWaiter(true, {"arc-tos-root", "arc-location-service"})
       ->Wait();
@@ -197,8 +195,7 @@
 
   const std::string button_to_click =
       accept_terms ? "arc-tos-accept-button" : "arc-tos-skip-button";
-  test::OobeJS().Evaluate(
-      test::GetOobeElementPath({"arc-tos-root", button_to_click}) + ".click()");
+  test::OobeJS().TapOnPath({"arc-tos-root", button_to_click});
 
   OobeScreenExitWaiter(ArcTermsOfServiceScreenView::kScreenId).Wait();
   LOG(INFO) << "OobeInteractiveUITest: 'arc-tos' screen done.";
diff --git a/chrome/browser/chromeos/login/password_change_browsertest.cc b/chrome/browser/chromeos/login/password_change_browsertest.cc
index 5cb9abab..65dde0a 100644
--- a/chrome/browser/chromeos/login/password_change_browsertest.cc
+++ b/chrome/browser/chromeos/login/password_change_browsertest.cc
@@ -66,7 +66,8 @@
 
  private:
   base::OnceClosure session_active_callback_;
-  ScopedObserver<session_manager::SessionManager, SessionStartWaiter>
+  ScopedObserver<session_manager::SessionManager,
+                 session_manager::SessionManagerObserver>
       session_observer_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SessionStartWaiter);
diff --git a/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc b/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc
index c3bbc19..8885d70 100644
--- a/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc
+++ b/chrome/browser/chromeos/login/screens/demo_preferences_screen.cc
@@ -41,7 +41,6 @@
     DemoPreferencesScreenView* view,
     const ScreenExitCallback& exit_callback)
     : BaseScreen(DemoPreferencesScreenView::kScreenId),
-      input_manager_observer_(this),
       view_(view),
       exit_callback_(exit_callback) {
   DCHECK(view_);
diff --git a/chrome/browser/chromeos/login/screens/demo_preferences_screen.h b/chrome/browser/chromeos/login/screens/demo_preferences_screen.h
index 3351647..171ee135 100644
--- a/chrome/browser/chromeos/login/screens/demo_preferences_screen.h
+++ b/chrome/browser/chromeos/login/screens/demo_preferences_screen.h
@@ -63,8 +63,9 @@
   // restored if user presses back button.
   std::string initial_input_method_;
 
-  ScopedObserver<input_method::InputMethodManager, DemoPreferencesScreen>
-      input_manager_observer_;
+  ScopedObserver<input_method::InputMethodManager,
+                 input_method::InputMethodManager::Observer>
+      input_manager_observer_{this};
 
   DemoPreferencesScreenView* view_;
   ScreenExitCallback exit_callback_;
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_screen.cc b/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
index 908897c9..7beaddc 100644
--- a/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
+++ b/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
@@ -18,7 +18,6 @@
 #include "components/consent_auditor/consent_auditor.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
-#include "components/sync/driver/sync_service.h"
 #include "components/user_manager/user_manager.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_screen.h b/chrome/browser/chromeos/login/screens/sync_consent_screen.h
index cc5b832..af40b60 100644
--- a/chrome/browser/chromeos/login/screens/sync_consent_screen.h
+++ b/chrome/browser/chromeos/login/screens/sync_consent_screen.h
@@ -13,6 +13,7 @@
 #include "base/scoped_observer.h"
 #include "chrome/browser/chromeos/login/screens/base_screen.h"
 #include "chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h"
+#include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_service_observer.h"
 #include "components/user_manager/user.h"
 
diff --git a/chrome/browser/chromeos/login/test/dialog_window_waiter.cc b/chrome/browser/chromeos/login/test/dialog_window_waiter.cc
index f681bc7..d9d48655f 100644
--- a/chrome/browser/chromeos/login/test/dialog_window_waiter.cc
+++ b/chrome/browser/chromeos/login/test/dialog_window_waiter.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/chromeos/login/test/dialog_window_waiter.h"
 
 #include "ui/aura/env.h"
-#include "ui/aura/window.h"
 #include "ui/views/widget/widget.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/login/test/dialog_window_waiter.h b/chrome/browser/chromeos/login/test/dialog_window_waiter.h
index 483080a..79bd849 100644
--- a/chrome/browser/chromeos/login/test/dialog_window_waiter.h
+++ b/chrome/browser/chromeos/login/test/dialog_window_waiter.h
@@ -11,6 +11,7 @@
 #include "base/run_loop.h"
 #include "base/scoped_observer.h"
 #include "ui/aura/env_observer.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 
 namespace chromeos {
@@ -50,7 +51,7 @@
   base::RunLoop run_loop_;
 
   std::set<aura::Window*> dialog_windows_;
-  ScopedObserver<aura::Window, DialogWindowWaiter> window_observer_{this};
+  ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this};
 
   DISALLOW_COPY_AND_ASSIGN(DialogWindowWaiter);
 };
diff --git a/chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.h b/chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.h
index ce9aaf7..1ff46007b 100644
--- a/chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.h
+++ b/chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.h
@@ -45,7 +45,7 @@
 
   State state_ = State::IDLE;
 
-  ScopedObserver<OobeUI, OobeScreenExitWaiter> oobe_ui_observer_{this};
+  ScopedObserver<OobeUI, OobeUI::Observer> oobe_ui_observer_{this};
 
   std::unique_ptr<base::RunLoop> run_loop_;
 
diff --git a/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc b/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc
index c45c4a3..a7326a2 100644
--- a/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc
+++ b/chrome/browser/chromeos/login/test/oobe_screen_waiter.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/window.h"
 #include "ui/views/controls/webview/webview.h"
 #include "ui/views/view.h"
 
diff --git a/chrome/browser/chromeos/login/test/oobe_screen_waiter.h b/chrome/browser/chromeos/login/test/oobe_screen_waiter.h
index c737b1e..4cbb6da 100644
--- a/chrome/browser/chromeos/login/test/oobe_screen_waiter.h
+++ b/chrome/browser/chromeos/login/test/oobe_screen_waiter.h
@@ -10,6 +10,7 @@
 #include "chrome/browser/chromeos/login/oobe_screen.h"
 #include "chrome/browser/chromeos/login/test/test_condition_waiter.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 
 namespace base {
@@ -18,8 +19,6 @@
 
 namespace chromeos {
 
-class OobeUI;
-
 // A waiter that blocks until the target oobe screen is reached.
 class OobeScreenWaiter : public OobeUI::Observer,
                          public test::TestConditionWaiter,
@@ -76,9 +75,10 @@
   // visible. True by default.
   bool check_native_window_visible_ = true;
 
-  ScopedObserver<OobeUI, OobeScreenWaiter> oobe_ui_observer_{this};
+  ScopedObserver<OobeUI, OobeUI::Observer> oobe_ui_observer_{this};
 
-  ScopedObserver<aura::Window, OobeScreenWaiter> native_window_observer_{this};
+  ScopedObserver<aura::Window, aura::WindowObserver> native_window_observer_{
+      this};
 
   std::unique_ptr<base::RunLoop> run_loop_;
 
diff --git a/chrome/browser/chromeos/login/test/oobe_window_visibility_waiter.cc b/chrome/browser/chromeos/login/test/oobe_window_visibility_waiter.cc
index 9b2b194..cf22f0f7 100644
--- a/chrome/browser/chromeos/login/test/oobe_window_visibility_waiter.cc
+++ b/chrome/browser/chromeos/login/test/oobe_window_visibility_waiter.cc
@@ -7,7 +7,6 @@
 #include "base/run_loop.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "content/public/browser/web_contents.h"
-#include "ui/aura/window.h"
 #include "ui/gfx/native_widget_types.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/login/test/oobe_window_visibility_waiter.h b/chrome/browser/chromeos/login/test/oobe_window_visibility_waiter.h
index f8720c8..f1d30e3 100644
--- a/chrome/browser/chromeos/login/test/oobe_window_visibility_waiter.h
+++ b/chrome/browser/chromeos/login/test/oobe_window_visibility_waiter.h
@@ -8,12 +8,9 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 
-namespace aura {
-class Window;
-}
-
 namespace chromeos {
 
 // Waits for the window that hosts OOBE UI changes visibility to target value.
@@ -36,8 +33,7 @@
 
   const bool target_visibility_;
   base::OnceClosure wait_stop_closure_;
-  ScopedObserver<aura::Window, OobeWindowVisibilityWaiter> window_observer_{
-      this};
+  ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this};
 
   DISALLOW_COPY_AND_ASSIGN(OobeWindowVisibilityWaiter);
 };
diff --git a/chrome/browser/chromeos/login/ui/kiosk_app_menu_controller.h b/chrome/browser/chromeos/login/ui/kiosk_app_menu_controller.h
index 710b7164..257e6b3 100644
--- a/chrome/browser/chromeos/login/ui/kiosk_app_menu_controller.h
+++ b/chrome/browser/chromeos/login/ui/kiosk_app_menu_controller.h
@@ -37,8 +37,10 @@
  private:
   void LaunchApp(const ash::KioskAppMenuEntry& app);
 
-  ScopedObserver<KioskAppManager, KioskAppMenuController> kiosk_observer_{this};
-  ScopedObserver<ArcKioskAppManager, KioskAppMenuController>
+  ScopedObserver<KioskAppManager, KioskAppManagerObserver> kiosk_observer_{
+      this};
+  ScopedObserver<ArcKioskAppManager,
+                 ArcKioskAppManager::ArcKioskAppManagerObserver>
       arc_kiosk_observer_{this};
 
   base::WeakPtrFactory<KioskAppMenuController> weak_factory_{this};
diff --git a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
index 48488b9..6c1b841 100644
--- a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
+++ b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
@@ -11,7 +11,6 @@
 #include "ash/public/cpp/login_screen.h"
 #include "ash/public/cpp/login_screen_model.h"
 #include "ash/public/cpp/shell_window_ids.h"
-#include "ash/public/cpp/tablet_mode.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host_mojo.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
@@ -27,7 +26,6 @@
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/display/display.h"
-#include "ui/display/screen.h"
 #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
 #include "ui/views/controls/webview/web_dialog_view.h"
 #include "ui/views/focus/focus_manager.h"
diff --git a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h
index 2467600d..0826e44 100644
--- a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h
+++ b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "ash/public/cpp/login_types.h"
+#include "ash/public/cpp/tablet_mode.h"
 #include "ash/public/cpp/tablet_mode_observer.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -18,20 +19,13 @@
 #include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "ui/display/display_observer.h"
+#include "ui/display/screen.h"
 #include "ui/web_dialogs/web_dialog_delegate.h"
 
-namespace ash {
-class TabletMode;
-}
-
 namespace content {
 class WebContents;
 }
 
-namespace display {
-class Screen;
-}
-
 namespace ui {
 class Accelerator;
 }
@@ -43,11 +37,10 @@
 
 namespace chromeos {
 
+class CaptivePortalDialogDelegate;
 class LoginDisplayHostMojo;
 class OobeUI;
 
-class CaptivePortalDialogDelegate;
-
 // This class manages the behavior of the Oobe UI dialog.
 // And its lifecycle is managed by the widget created in Show().
 //   WebDialogView<----delegate_----OobeUIDialogDelegate
@@ -145,7 +138,7 @@
   ScopedObserver<ChromeKeyboardControllerClient,
                  ChromeKeyboardControllerClient::Observer>
       keyboard_observer_{this};
-  ScopedObserver<CaptivePortalWindowProxy, OobeUIDialogDelegate>
+  ScopedObserver<CaptivePortalWindowProxy, CaptivePortalWindowProxy::Observer>
       captive_portal_observer_{this};
 
   std::map<ui::Accelerator, std::string> accel_map_;
diff --git a/chrome/browser/chromeos/note_taking_helper.cc b/chrome/browser/chromeos/note_taking_helper.cc
index ee4c8762..88460fef 100644
--- a/chrome/browser/chromeos/note_taking_helper.cc
+++ b/chrome/browser/chromeos/note_taking_helper.cc
@@ -363,7 +363,6 @@
 NoteTakingHelper::NoteTakingHelper()
     : launch_chrome_app_callback_(
           base::Bind(&apps::LaunchPlatformAppWithAction)),
-      extension_registry_observer_(this),
       note_taking_controller_client_(
           std::make_unique<NoteTakingControllerClient>(this)) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/chromeos/note_taking_helper.h b/chrome/browser/chromeos/note_taking_helper.h
index e2f087c5..9b21b22 100644
--- a/chrome/browser/chromeos/note_taking_helper.h
+++ b/chrome/browser/chromeos/note_taking_helper.h
@@ -20,6 +20,7 @@
 #include "components/arc/intent_helper/arc_intent_helper_observer.h"
 #include "components/arc/mojom/intent_helper.mojom.h"
 #include "components/prefs/pref_change_registrar.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
 #include "extensions/common/extension.h"
 
@@ -35,7 +36,6 @@
 
 namespace extensions {
 class Extension;
-class ExtensionRegistry;
 namespace api {
 namespace app_runtime {
 struct ActionData;
@@ -295,7 +295,7 @@
   // Tracks ExtensionRegistry observation for different profiles.
   ScopedObserver<extensions::ExtensionRegistry,
                  extensions::ExtensionRegistryObserver>
-      extension_registry_observer_;
+      extension_registry_observer_{this};
 
   // The profile for which lock screen apps are enabled,
   Profile* profile_with_enabled_lock_screen_apps_ = nullptr;
diff --git a/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.cc b/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.cc
index 3600cbb..684b291a 100644
--- a/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.cc
+++ b/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.cc
@@ -34,7 +34,6 @@
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/viz/public/mojom/compositing/video_detector_observer.mojom.h"
 #include "ui/aura/env.h"
-#include "ui/base/user_activity/user_activity_detector.h"
 
 namespace chromeos {
 namespace power {
@@ -112,8 +111,6 @@
     std::unique_ptr<base::RepeatingTimer> periodic_timer)
     : periodic_timer_(std::move(periodic_timer)),
       ukm_logger_(std::move(ukm_logger)),
-      user_activity_observer_(this),
-      power_manager_client_observer_(this),
       accessibility_manager_(accessibility_manager),
       magnification_manager_(magnification_manager),
       binding_(this, std::move(request)),
diff --git a/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.h b/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.h
index 657eff6..0b7e031 100644
--- a/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.h
+++ b/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.h
@@ -18,16 +18,13 @@
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/viz/public/mojom/compositing/video_detector_observer.mojom.h"
+#include "ui/base/user_activity/user_activity_detector.h"
 #include "ui/base/user_activity/user_activity_observer.h"
 
 namespace base {
 class RepeatingTimer;
 }  // namespace base
 
-namespace ui {
-class UserActivityDetector;
-}  // namespace ui
-
 namespace chromeos {
 
 class AccessibilityManager;
@@ -112,10 +109,10 @@
   const std::unique_ptr<AdaptiveScreenBrightnessUkmLogger> ukm_logger_;
 
   ScopedObserver<ui::UserActivityDetector, ui::UserActivityObserver>
-      user_activity_observer_;
+      user_activity_observer_{this};
   ScopedObserver<chromeos::PowerManagerClient,
                  chromeos::PowerManagerClient::Observer>
-      power_manager_client_observer_;
+      power_manager_client_observer_{this};
 
   AccessibilityManager* const accessibility_manager_;
   MagnificationManager* const magnification_manager_;
diff --git a/chrome/browser/chromeos/printing/bulk_printers_calculator_factory.cc b/chrome/browser/chromeos/printing/bulk_printers_calculator_factory.cc
index fd0fbba..d939d2f 100644
--- a/chrome/browser/chromeos/printing/bulk_printers_calculator_factory.cc
+++ b/chrome/browser/chromeos/printing/bulk_printers_calculator_factory.cc
@@ -6,8 +6,6 @@
 
 #include "base/no_destructor.h"
 #include "chrome/browser/chromeos/printing/bulk_printers_calculator.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/profiles/profile.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/user.h"
 
@@ -29,16 +27,6 @@
   return printers_by_user_[account_id]->AsWeakPtr();
 }
 
-base::WeakPtr<BulkPrintersCalculator>
-BulkPrintersCalculatorFactory::GetForProfile(Profile* profile) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  const user_manager::User* user =
-      ProfileHelper::Get()->GetUserByProfile(profile);
-  if (!user)
-    return nullptr;
-  return GetForAccountId(user->GetAccountId());
-}
-
 void BulkPrintersCalculatorFactory::RemoveForUserId(
     const AccountId& account_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chrome/browser/chromeos/printing/bulk_printers_calculator_factory.h b/chrome/browser/chromeos/printing/bulk_printers_calculator_factory.h
index a30cc0a..3a4bd78 100644
--- a/chrome/browser/chromeos/printing/bulk_printers_calculator_factory.h
+++ b/chrome/browser/chromeos/printing/bulk_printers_calculator_factory.h
@@ -13,7 +13,6 @@
 #include "base/sequence_checker.h"
 
 class AccountId;
-class Profile;
 
 namespace chromeos {
 
@@ -32,21 +31,14 @@
   // |account_id|.
   // If requested BulkPrintersCalculator does not exist, the object is
   // created and registered. The returned object remains valid until
-  // RemoveForUserId or Shutdown is called.
+  // RemoveForUserId or Shutdown is called. It never returns nullptr.
   base::WeakPtr<BulkPrintersCalculator> GetForAccountId(
       const AccountId& account_id);
 
-  // Returns a WeakPtr to the BulkPrintersCalculator registered for |profile|
-  // which could be nullptr if |profile| does not map to a valid AccountId.
-  // If requested BulkPrintersCalculator does not exist, the object is
-  // created and registered. The returned object remains valid until
-  // RemoveForUserId or Shutdown is called.
-  base::WeakPtr<BulkPrintersCalculator> GetForProfile(Profile* profile);
-
   // Returns a WeakPtr to the BulkPrintersCalculator registered for the device.
   // If requested BulkPrintersCalculator does not exist, the object is
   // created and registered. The returned object remains valid until Shutdown is
-  // called.
+  // called. It never returns nullptr.
   base::WeakPtr<BulkPrintersCalculator> GetForDevice();
 
   // Deletes the BulkPrintersCalculator registered for |account_id|.
diff --git a/chrome/browser/chromeos/printing/calculators_policies_binder.cc b/chrome/browser/chromeos/printing/calculators_policies_binder.cc
index 8a5f474..7c7714d8 100644
--- a/chrome/browser/chromeos/printing/calculators_policies_binder.cc
+++ b/chrome/browser/chromeos/printing/calculators_policies_binder.cc
@@ -11,6 +11,7 @@
 
 #include "chrome/browser/chromeos/printing/bulk_printers_calculator.h"
 #include "chrome/browser/chromeos/printing/bulk_printers_calculator_factory.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
@@ -18,6 +19,7 @@
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
+#include "components/user_manager/user.h"
 
 namespace chromeos {
 
@@ -69,9 +71,15 @@
       BindSettings(kDeviceNativePrintersWhitelist,
                    &CalculatorsPoliciesBinderImpl::UpdateDeviceWhitelist);
     }
+    // Calculate account_id_.
+    const user_manager::User* user =
+        ProfileHelper::Get()->GetUserByProfile(profile);
+    if (user) {
+      account_id_ = user->GetAccountId();
+      user_printers_ =
+          BulkPrintersCalculatorFactory::Get()->GetForAccountId(account_id_);
+    }
     // Bind user policies to corresponding instance of BulkPrintersCalculator.
-    user_printers_ =
-        BulkPrintersCalculatorFactory::Get()->GetForProfile(profile);
     if (user_printers_ && ++(BindingsCount()[user_printers_.get()]) == 1) {
       BindPref(prefs::kRecommendedNativePrintersAccessMode,
                &CalculatorsPoliciesBinderImpl::UpdateUserAccessMode);
@@ -89,6 +97,7 @@
     }
     if (user_printers_ && --(BindingsCount()[user_printers_.get()]) == 0) {
       BindingsCount().erase(user_printers_.get());
+      BulkPrintersCalculatorFactory::Get()->RemoveForUserId(account_id_);
     }
   }
 
@@ -99,33 +108,45 @@
     if (!settings_->GetInteger(kDeviceNativePrintersAccessMode, &mode_val)) {
       mode_val = BulkPrintersCalculator::AccessMode::UNSET;
     }
-    device_printers_->SetAccessMode(ConvertToAccessMode(mode_val));
+    if (device_printers_) {
+      device_printers_->SetAccessMode(ConvertToAccessMode(mode_val));
+    }
   }
 
   void UpdateDeviceBlacklist() {
-    device_printers_->SetBlacklist(
-        FromSettings(kDeviceNativePrintersBlacklist));
+    if (device_printers_) {
+      device_printers_->SetBlacklist(
+          FromSettings(kDeviceNativePrintersBlacklist));
+    }
   }
 
   void UpdateDeviceWhitelist() {
-    device_printers_->SetWhitelist(
-        FromSettings(kDeviceNativePrintersWhitelist));
+    if (device_printers_) {
+      device_printers_->SetWhitelist(
+          FromSettings(kDeviceNativePrintersWhitelist));
+    }
   }
 
   void UpdateUserAccessMode() {
-    user_printers_->SetAccessMode(
-        ConvertToAccessMode(profile_->GetPrefs()->GetInteger(
-            prefs::kRecommendedNativePrintersAccessMode)));
+    if (user_printers_) {
+      user_printers_->SetAccessMode(
+          ConvertToAccessMode(profile_->GetPrefs()->GetInteger(
+              prefs::kRecommendedNativePrintersAccessMode)));
+    }
   }
 
   void UpdateUserBlacklist() {
-    user_printers_->SetBlacklist(
-        FromPrefs(prefs::kRecommendedNativePrintersBlacklist));
+    if (user_printers_) {
+      user_printers_->SetBlacklist(
+          FromPrefs(prefs::kRecommendedNativePrintersBlacklist));
+    }
   }
 
   void UpdateUserWhitelist() {
-    user_printers_->SetWhitelist(
-        FromPrefs(prefs::kRecommendedNativePrintersWhitelist));
+    if (user_printers_) {
+      user_printers_->SetWhitelist(
+          FromPrefs(prefs::kRecommendedNativePrintersWhitelist));
+    }
   }
 
   typedef void (CalculatorsPoliciesBinderImpl::*SimpleMethod)();
@@ -160,7 +181,9 @@
     return ConvertToVector(profile_->GetPrefs()->GetList(policy_name));
   }
 
-  // Device and user bulk printers. Unowned.
+  // Device and user bulk printers calculator. Unowned. They both may be set to
+  // nullptr during system shutdown. The user bulk printers calculator is also
+  // set to nullptr when corresponding profile is being destroyed.
   base::WeakPtr<BulkPrintersCalculator> device_printers_;
   base::WeakPtr<BulkPrintersCalculator> user_printers_;
 
@@ -168,6 +191,7 @@
   CrosSettings* settings_;
   std::list<std::unique_ptr<CrosSettings::ObserverSubscription>> subscriptions_;
   Profile* profile_;
+  AccountId account_id_;
   PrefChangeRegistrar pref_change_registrar_;
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chrome/browser/chromeos/printing/enterprise_printers_provider.cc b/chrome/browser/chromeos/printing/enterprise_printers_provider.cc
index d96fb78..5cb96ea 100644
--- a/chrome/browser/chromeos/printing/enterprise_printers_provider.cc
+++ b/chrome/browser/chromeos/printing/enterprise_printers_provider.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/chromeos/printing/bulk_printers_calculator.h"
 #include "chrome/browser/chromeos/printing/bulk_printers_calculator_factory.h"
 #include "chrome/browser/chromeos/printing/calculators_policies_binder.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/common/pref_names.h"
@@ -21,6 +22,7 @@
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
+#include "components/user_manager/user.h"
 
 namespace chromeos {
 
@@ -54,10 +56,14 @@
       device_printers_->AddObserver(this);
       RecalculateCompleteFlagForDevicePrinters();
     }
-    // Get instance of BulkPrintersCalculator for user policies.
-    user_printers_ =
-        BulkPrintersCalculatorFactory::Get()->GetForProfile(profile);
-    if (user_printers_) {
+    // Calculate account_id_ and get instance of BulkPrintersCalculator for user
+    // policies.
+    const user_manager::User* user =
+        ProfileHelper::Get()->GetUserByProfile(profile);
+    if (user) {
+      account_id_ = user->GetAccountId();
+      user_printers_ =
+          BulkPrintersCalculatorFactory::Get()->GetForAccountId(account_id_);
       user_printers_->AddObserver(this);
       RecalculateCompleteFlagForUserPrinters();
     }
@@ -71,8 +77,10 @@
   ~EnterprisePrintersProviderImpl() override {
     if (device_printers_)
       device_printers_->RemoveObserver(this);
-    if (user_printers_)
+    if (user_printers_) {
       user_printers_->RemoveObserver(this);
+      BulkPrintersCalculatorFactory::Get()->RemoveForUserId(account_id_);
+    }
   }
 
   void AddObserver(EnterprisePrintersProvider::Observer* observer) override {
@@ -221,6 +229,7 @@
 
   // Profile (user) settings.
   Profile* profile_;
+  AccountId account_id_;
   PrefChangeRegistrar pref_change_registrar_;
 
   base::ObserverList<EnterprisePrintersProvider::Observer>::Unchecked
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc
index f3d0977..59a052b 100644
--- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.cc
@@ -43,7 +43,7 @@
 // Note: the list size must be kept in sync with
 // |kWilcoDtcSupportdHostOriginsSize|.
 const char* const kWilcoDtcSupportdHostOrigins[] = {
-    "chrome-extension://echlnkcmdobkdgcjgjbiceoceeoenjkj/"};
+    "chrome-extension://okdnlenpdegbpdgniggponebnbkbeeca/"};
 
 // Size of |kWilcoDtcSupportdHostOrigins| array.
 const size_t kWilcoDtcSupportdHostOriginsSize =
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index c2a1c75..8005671e 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -200,9 +200,17 @@
 }
 
 std::unique_ptr<base::DictionaryValue> BuildObjectForResponse(
-    const net::HttpResponseHeaders* rh) {
+    const net::HttpResponseHeaders* rh,
+    bool success) {
   auto response = std::make_unique<base::DictionaryValue>();
-  response->SetInteger("statusCode", rh ? rh->response_code() : 200);
+  int responseCode = 200;
+  if (rh) {
+    responseCode = rh->response_code();
+  } else if (!success) {
+    // In case of no headers, assume file:// URL and failed to load
+    responseCode = 404;
+  }
+  response->SetInteger("statusCode", responseCode);
 
   auto headers = std::make_unique<base::DictionaryValue>();
   size_t iterator = 0;
@@ -419,7 +427,7 @@
   }
 
   void OnComplete(bool success) override {
-    auto response = BuildObjectForResponse(response_headers_.get());
+    auto response = BuildObjectForResponse(response_headers_.get(), success);
     callback_.Run(response.get());
 
     bindings_->loaders_.erase(bindings_->loaders_.find(this));
diff --git a/chrome/browser/download/download_status_updater.cc b/chrome/browser/download/download_status_updater.cc
index b21aa1cc..1b3e183 100644
--- a/chrome/browser/download/download_status_updater.cc
+++ b/chrome/browser/download/download_status_updater.cc
@@ -13,10 +13,6 @@
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-#include "ui/views/linux_ui/linux_ui.h"
-#endif
-
 namespace {
 
 // DownloadStatusUpdater::UpdateAppIconDownloadProgress() expects to only be
@@ -133,19 +129,9 @@
   UpdateAppIconDownloadProgress(item);
 }
 
-#if defined(OS_ANDROID) || (defined(USE_AURA) && !defined(OS_WIN))
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
 void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
     download::DownloadItem* download) {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-  const views::LinuxUI* linux_ui = views::LinuxUI::instance();
-  if (linux_ui) {
-    float progress = 0;
-    int download_count = 0;
-    GetProgress(&progress, &download_count);
-    linux_ui->SetDownloadCount(download_count);
-    linux_ui->SetProgressFraction(progress);
-  }
-#endif
   // TODO(avi): Implement for Android?
 }
 #endif
diff --git a/chrome/browser/ui/libgtkui/unity_service.cc b/chrome/browser/download/download_status_updater_linux.cc
similarity index 75%
rename from chrome/browser/ui/libgtkui/unity_service.cc
rename to chrome/browser/download/download_status_updater_linux.cc
index 4678006..6d79178 100644
--- a/chrome/browser/ui/libgtkui/unity_service.cc
+++ b/chrome/browser/download/download_status_updater_linux.cc
@@ -2,36 +2,37 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/libgtkui/unity_service.h"
+#include "chrome/browser/download/download_status_updater.h"
 
 #include <dlfcn.h>
-#include <gtk/gtk.h>
 
 #include <memory>
 #include <string>
 
 #include "base/environment.h"
 #include "base/nix/xdg_util.h"
-#include "chrome/browser/ui/libgtkui/gtk_util.h"
+#include "chrome/common/channel_info.h"
+#include "ui/base/glib/glib_integers.h"
 
 // Unity data typedefs.
 typedef struct _UnityInspector UnityInspector;
 typedef UnityInspector* (*unity_inspector_get_default_func)(void);
-typedef gboolean (*unity_inspector_get_unity_running_func)
-    (UnityInspector* self);
+typedef gboolean (*unity_inspector_get_unity_running_func)(
+    UnityInspector* self);
 
 typedef struct _UnityLauncherEntry UnityLauncherEntry;
-typedef UnityLauncherEntry* (*unity_launcher_entry_get_for_desktop_id_func)
-    (const gchar* desktop_id);
+typedef UnityLauncherEntry* (*unity_launcher_entry_get_for_desktop_id_func)(
+    const gchar* desktop_id);
 typedef void (*unity_launcher_entry_set_count_func)(UnityLauncherEntry* self,
-                                               gint64 value);
-typedef void (*unity_launcher_entry_set_count_visible_func)
-    (UnityLauncherEntry* self, gboolean value);
+                                                    gint64 value);
+typedef void (*unity_launcher_entry_set_count_visible_func)(
+    UnityLauncherEntry* self,
+    gboolean value);
 typedef void (*unity_launcher_entry_set_progress_func)(UnityLauncherEntry* self,
                                                        gdouble value);
-typedef void (*unity_launcher_entry_set_progress_visible_func)
-    (UnityLauncherEntry* self, gboolean value);
-
+typedef void (*unity_launcher_entry_set_progress_visible_func)(
+    UnityLauncherEntry* self,
+    gboolean value);
 
 namespace {
 
@@ -59,8 +60,7 @@
   attempted_load = true;
 
   std::unique_ptr<base::Environment> env(base::Environment::Create());
-  base::nix::DesktopEnvironment desktop_env =
-      GetDesktopEnvironment(env.get());
+  base::nix::DesktopEnvironment desktop_env = GetDesktopEnvironment(env.get());
 
   // The "icon-tasks" KDE task manager also honors Unity Launcher API.
   if (desktop_env != base::nix::DESKTOP_ENVIRONMENT_UNITY &&
@@ -92,12 +92,11 @@
       reinterpret_cast<unity_launcher_entry_get_for_desktop_id_func>(
           dlsym(unity_lib, "unity_launcher_entry_get_for_desktop_id"));
   if (entry_get_for_desktop_id) {
-    std::string desktop_id = libgtkui::GetDesktopName(env.get());
+    std::string desktop_id = chrome::GetDesktopName(env.get());
     chrome_entry = entry_get_for_desktop_id(desktop_id.c_str());
 
-    entry_set_count =
-        reinterpret_cast<unity_launcher_entry_set_count_func>(
-            dlsym(unity_lib, "unity_launcher_entry_set_count"));
+    entry_set_count = reinterpret_cast<unity_launcher_entry_set_count_func>(
+        dlsym(unity_lib, "unity_launcher_entry_set_count"));
 
     entry_set_count_visible =
         reinterpret_cast<unity_launcher_entry_set_count_visible_func>(
@@ -113,21 +112,11 @@
   }
 }
 
-}  // namespace
-
-
-namespace unity {
-
 bool IsRunning() {
-  EnsureLibUnityLoaded();
-  if (inspector && get_unity_running)
-    return get_unity_running(inspector);
-
-  return false;
+  return inspector && get_unity_running && get_unity_running(inspector);
 }
 
 void SetDownloadCount(int count) {
-  EnsureLibUnityLoaded();
   if (chrome_entry && entry_set_count && entry_set_count_visible) {
     entry_set_count(chrome_entry, count);
     entry_set_count_visible(chrome_entry, count != 0);
@@ -135,7 +124,6 @@
 }
 
 void SetProgressFraction(float percentage) {
-  EnsureLibUnityLoaded();
   if (chrome_entry && entry_set_progress && entry_set_progress_visible) {
     entry_set_progress(chrome_entry, percentage);
     entry_set_progress_visible(chrome_entry,
@@ -143,4 +131,17 @@
   }
 }
 
-}  // namespace unity
+}  // namespace
+
+void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
+    download::DownloadItem* download) {
+  // Only implemented on Unity for now.
+  EnsureLibUnityLoaded();
+  if (!IsRunning())
+    return;
+  float progress = 0;
+  int download_count = 0;
+  GetProgress(&progress, &download_count);
+  SetDownloadCount(download_count);
+  SetProgressFraction(progress);
+}
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
index 507dbad..1de2320 100644
--- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
+++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
@@ -257,8 +257,7 @@
 
 }  // namespace
 
-// Flaky: crbug.com/1011606.
-IN_PROC_BROWSER_TEST_F(CertificateProviderApiTest, DISABLED_Basic) {
+IN_PROC_BROWSER_TEST_F(CertificateProviderApiTest, Basic) {
   // Start an HTTPS test server that requests a client certificate.
   net::SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index 9fdc80ef..b8b1abc 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -354,6 +354,8 @@
       return input_method_private::AUTO_CAPITALIZE_TYPE_CHARACTERS;
     if (flags & ui::TEXT_INPUT_FLAG_AUTOCAPITALIZE_WORDS)
       return input_method_private::AUTO_CAPITALIZE_TYPE_WORDS;
+    if (flags & ui::TEXT_INPUT_FLAG_AUTOCAPITALIZE_SENTENCES)
+      return input_method_private::AUTO_CAPITALIZE_TYPE_SENTENCES;
 
     // Autocapitalize flag may be missing for native text fields.
     // See https://crbug.com/1002713.
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
index 48363ce..3a3d705 100644
--- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
+++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
@@ -22,6 +22,8 @@
 #include "components/policy/core/common/cloud/cloud_policy_client.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
 #include "components/policy/core/common/cloud/realtime_reporting_job_configuration.h"
+#include "components/prefs/pref_service.h"
+#include "components/safe_browsing/common/safe_browsing_prefs.h"
 #include "components/safe_browsing/proto/webprotect.pb.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "content/public/browser/browser_context.h"
@@ -70,7 +72,18 @@
     content::BrowserContext* context)
     : context_(context) {
   event_router_ = EventRouter::Get(context_);
-  InitRealtimeReportingClient();
+
+  // g_browser_process and/or g_browser_process->local_state() may be null
+  // in tests.
+  if (g_browser_process && g_browser_process->local_state()) {
+    RealtimeReportingPrefChanged(std::string());
+    registrar_.Init(g_browser_process->local_state());
+    registrar_.Add(
+        prefs::kUnsafeEventsReportingEnabled,
+        base::BindRepeating(
+            &SafeBrowsingPrivateEventRouter::RealtimeReportingPrefChanged,
+            base::Unretained(this)));
+  }
 }
 
 SafeBrowsingPrivateEventRouter::~SafeBrowsingPrivateEventRouter() {}
@@ -98,7 +111,7 @@
     event_router_->BroadcastEvent(std::move(extension_event));
   }
 
-  if (client_) {
+  if (IsRealtimeReportingEnabled()) {
     // Convert |params| to a real-time event dictionary and report it.
     base::Value event(base::Value::Type::DICTIONARY);
     event.SetStringKey(kKeyUrl, params.url);
@@ -123,7 +136,7 @@
     event_router_->BroadcastEvent(std::move(extension_event));
   }
 
-  if (client_) {
+  if (IsRealtimeReportingEnabled()) {
     // Convert |params| to a real-time event dictionary and report it.
     base::Value event(base::Value::Type::DICTIONARY);
     event.SetStringKey(kKeyUserName, user_name);
@@ -154,7 +167,7 @@
     event_router_->BroadcastEvent(std::move(extension_event));
   }
 
-  if (client_) {
+  if (IsRealtimeReportingEnabled()) {
     // Convert |params| to a real-time event dictionary and report it.
     base::Value event(base::Value::Type::DICTIONARY);
     event.SetStringKey(kKeyUrl, params.url);
@@ -190,7 +203,7 @@
     event_router_->BroadcastEvent(std::move(extension_event));
   }
 
-  if (client_) {
+  if (IsRealtimeReportingEnabled()) {
     // Convert |params| to a real-time event dictionary and report it.
     base::Value event(base::Value::Type::DICTIONARY);
     event.SetStringKey(kKeyUrl, params.url);
@@ -227,7 +240,7 @@
     event_router_->BroadcastEvent(std::move(extension_event));
   }
 
-  if (client_) {
+  if (IsRealtimeReportingEnabled()) {
     // Convert |params| to a real-time event dictionary and report it.
     base::Value event(base::Value::Type::DICTIONARY);
     event.SetStringKey(kKeyUrl, params.url);
@@ -244,7 +257,7 @@
     const std::string& file_name,
     const std::string& download_digest_sha256,
     const std::string& threat_type) {
-  if (client_) {
+  if (IsRealtimeReportingEnabled()) {
     // Create a real-time event dictionary from the arguments and report it.
     base::Value event(base::Value::Type::DICTIONARY);
     event.SetStringKey(kKeyUrl, url.spec());
@@ -261,7 +274,7 @@
     const GURL& url,
     const std::string& file_name,
     const std::string& download_digest_sha256) {
-  if (client_) {
+  if (IsRealtimeReportingEnabled()) {
     // Create a real-time event dictionary from the arguments and report it.
     base::Value event(base::Value::Type::DICTIONARY);
     event.SetStringKey(kKeyUrl, url.spec());
@@ -282,7 +295,7 @@
     const GURL& url,
     const std::string& file_name,
     const std::string& download_digest_sha256) {
-  if (client_) {
+  if (IsRealtimeReportingEnabled()) {
     // Create a real-time event dictionary from the arguments and report it.
     base::Value event(base::Value::Type::DICTIONARY);
     event.SetStringKey(kKeyUrl, url.spec());
@@ -298,7 +311,7 @@
     const std::string& file_name,
     const std::string& download_digest_sha256,
     const std::string& threat_type) {
-  if (!client_)
+  if (!IsRealtimeReportingEnabled())
     return;
 
   // Create a real-time event dictionary and report it.
@@ -317,7 +330,7 @@
     const std::string& file_name,
     const std::string& download_digest_sha256,
     const std::string& threat_type) {
-  if (!client_)
+  if (!IsRealtimeReportingEnabled())
     return;
 
   // Create a real-time event dictionary and report it.
@@ -339,6 +352,10 @@
 
 void SafeBrowsingPrivateEventRouter::InitRealtimeReportingClient() {
 #if !defined(OS_CHROMEOS)
+  // If already initialized, do nothing.
+  if (client_)
+    return;
+
   // This method is not compiled on Chrome OS because
   // MachineLevelUserCloudPolicyController does not exist. Also,
   // policy::BrowserDMTokenStorage::Get()->RetrieveDMToken() doesn't return a
@@ -405,6 +422,21 @@
 #endif
 }
 
+bool SafeBrowsingPrivateEventRouter::IsRealtimeReportingEnabled() {
+  // g_browser_process and/or g_browser_process->local_state() may be null
+  // in tests.
+  return g_browser_process && g_browser_process->local_state() &&
+         g_browser_process->local_state()->GetBoolean(
+             prefs::kUnsafeEventsReportingEnabled);
+}
+
+void SafeBrowsingPrivateEventRouter::RealtimeReportingPrefChanged(
+    const std::string& pref) {
+  // If the reporting policy has been turned on, try to initialized now.
+  if (IsRealtimeReportingEnabled())
+    InitRealtimeReportingClient();
+}
+
 void SafeBrowsingPrivateEventRouter::ReportRealtimeEvent(const char* name,
                                                          base::Value event) {
   // Format the current time (UTC) in RFC3339 format.
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h
index 5771a928..fcc0b25 100644
--- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h
+++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/values.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "components/prefs/pref_change_registrar.h"
 
 namespace content {
 class BrowserContext;
@@ -142,6 +143,12 @@
   // with CBCM and the appropriate policies are enabled.
   void InitRealtimeReportingClient();
 
+  // Determines if the real-time reporting feature is enabled.
+  bool IsRealtimeReportingEnabled();
+
+  // Called whenever the real-time reporting policy changes.
+  void RealtimeReportingPrefChanged(const std::string& pref);
+
   // Report safe browsing event through real-time reporting channel, if enabled.
   void ReportRealtimeEvent(const char* name, base::Value event);
 
@@ -153,6 +160,7 @@
   signin::IdentityManager* identity_manager_ = nullptr;
   EventRouter* event_router_ = nullptr;
   std::unique_ptr<policy::CloudPolicyClient> client_;
+  PrefChangeRegistrar registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingPrivateEventRouter);
 };
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc
index 09d22582d..79136c1 100644
--- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc
+++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
 #include "components/policy/core/common/cloud/realtime_reporting_job_configuration.h"
+#include "components/safe_browsing/common/safe_browsing_prefs.h"
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/browser/test_event_router.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -108,10 +109,14 @@
                                           "PHISHING", -201);
   }
 
-  void SetUpRouters() {
-    event_router_ = extensions::CreateAndUseTestEventRouter(profile_);
-    SafeBrowsingPrivateEventRouterFactory::GetInstance()->SetTestingFactory(
-        profile_, base::BindRepeating(&BuildSafeBrowsingPrivateEventRouter));
+  void SetReportingPolicy(bool enabled) {
+    TestingBrowserProcess::GetGlobal()->local_state()->SetBoolean(
+        prefs::kUnsafeEventsReportingEnabled, enabled);
+
+    // If we are not enabling reporting, or if the client has already been
+    // set for testing, just return.
+    if (!enabled || client_)
+      return;
 
     // Set a mock cloud policy client in the router.  The router will own the
     // client, but a pointer to the client is maintained in the test class to
@@ -122,12 +127,20 @@
         ->SetCloudPolicyClientForTesting(std::move(client));
   }
 
+  void SetUpRouters(bool realtime_reporting_enable = true) {
+    event_router_ = extensions::CreateAndUseTestEventRouter(profile_);
+    SafeBrowsingPrivateEventRouterFactory::GetInstance()->SetTestingFactory(
+        profile_, base::BindRepeating(&BuildSafeBrowsingPrivateEventRouter));
+
+    SetReportingPolicy(realtime_reporting_enable);
+  }
+
  protected:
   content::BrowserTaskEnvironment task_environment_;
   TestingProfileManager profile_manager_;
   TestingProfile* profile_;
   extensions::TestEventRouter* event_router_ = nullptr;
-  policy::MockCloudPolicyClient* client_;
+  policy::MockCloudPolicyClient* client_ = nullptr;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingPrivateEventRouterTest);
@@ -323,4 +336,45 @@
   EXPECT_FALSE(
       *event->FindBoolKey(SafeBrowsingPrivateEventRouter::kKeyClickedThrough));
 }
+
+TEST_F(SafeBrowsingPrivateEventRouterTest, PolicyControlOnToOffIsDynamic) {
+  SetUpRouters();
+  SafeBrowsingEventObserver event_observer(
+      api::safe_browsing_private::OnSecurityInterstitialShown::kEventName);
+  event_router_->AddEventObserver(&event_observer);
+
+  EXPECT_CALL(*client_, UploadRealtimeReport(_, _)).Times(1);
+  TriggerOnSecurityInterstitialShownEvent();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1u, event_observer.PassEventArgs().GetList().size());
+  Mock::VerifyAndClearExpectations(client_);
+
+  // Now turn off policy.  This time no report should be generated.
+  SetReportingPolicy(false);
+  EXPECT_CALL(*client_, UploadRealtimeReport(_, _)).Times(0);
+  TriggerOnSecurityInterstitialShownEvent();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1u, event_observer.PassEventArgs().GetList().size());
+  Mock::VerifyAndClearExpectations(client_);
+}
+
+TEST_F(SafeBrowsingPrivateEventRouterTest, PolicyControlOffToOnIsDynamic) {
+  SetUpRouters(/*realtime_reporting_enable=*/false);
+  SafeBrowsingEventObserver event_observer(
+      api::safe_browsing_private::OnSecurityInterstitialShown::kEventName);
+  event_router_->AddEventObserver(&event_observer);
+
+  TriggerOnSecurityInterstitialShownEvent();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1u, event_observer.PassEventArgs().GetList().size());
+
+  // Now turn on policy.
+  SetReportingPolicy(true);
+  EXPECT_CALL(*client_, UploadRealtimeReport(_, _)).Times(1);
+  TriggerOnSecurityInterstitialShownEvent();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1u, event_observer.PassEventArgs().GetList().size());
+  Mock::VerifyAndClearExpectations(client_);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
index bdc582c..cd182798 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -595,29 +595,6 @@
 }
 
 // static
-void ChromeContentBrowserClientExtensionsPart::OverrideNavigationParams(
-    content::SiteInstance* site_instance,
-    ui::PageTransition* transition,
-    bool* is_renderer_initiated,
-    content::Referrer* referrer,
-    base::Optional<url::Origin>* initiator_origin) {
-  const Extension* extension =
-      ExtensionRegistry::Get(site_instance->GetBrowserContext())
-          ->enabled_extensions()
-          .GetExtensionOrAppByURL(site_instance->GetSiteURL());
-  if (!extension)
-    return;
-
-  // Hide the |referrer| for extension pages. We don't want sites to see a
-  // referrer of chrome-extension://<...>.
-  //
-  // OTOH, don't change |initiator_origin| - SameSite-cookies and Sec-Fetch-Site
-  // should still see the request as cross-site.
-  if (extension->is_extension())
-    *referrer = content::Referrer();
-}
-
-// static
 std::vector<url::Origin> ChromeContentBrowserClientExtensionsPart::
     GetOriginsRequiringDedicatedProcess() {
   std::vector<url::Origin> list;
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
index 737d6bf..6fe47f4 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
@@ -18,7 +18,6 @@
 #include "ui/base/page_transition_types.h"
 
 namespace content {
-struct Referrer;
 class RenderFrameHost;
 class RenderProcessHost;
 class ResourceContext;
@@ -77,12 +76,6 @@
                                      const GURL& first_party_url,
                                      const GURL& script_url,
                                      content::BrowserContext* context);
-  static void OverrideNavigationParams(
-      content::SiteInstance* site_instance,
-      ui::PageTransition* transition,
-      bool* is_renderer_initiated,
-      content::Referrer* referrer,
-      base::Optional<url::Origin>* initiator_origin);
   static std::vector<url::Origin> GetOriginsRequiringDedicatedProcess();
 
   // Helper function to call InfoMap::SetSigninProcess().
diff --git a/chrome/browser/extensions/navigation_observer_browsertest.cc b/chrome/browser/extensions/navigation_observer_browsertest.cc
index 290bbff..4a149fa9 100644
--- a/chrome/browser/extensions/navigation_observer_browsertest.cc
+++ b/chrome/browser/extensions/navigation_observer_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/extensions/navigation_observer.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/test/no_renderer_crashes_assertion.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
@@ -132,4 +133,45 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, NoExtensionsInRefererHeader) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  scoped_refptr<const Extension> extension =
+      ChromeTestExtensionLoader(profile()).LoadExtension(
+          test_data_dir_.AppendASCII("simple_with_file"));
+  ASSERT_TRUE(extension);
+  GURL page_url = extension->GetResourceURL("file.html");
+  ui_test_utils::NavigateToURL(browser(), page_url);
+
+  // Click a link in the extension.
+  GURL target_url = embedded_test_server()->GetURL("/echoheader?referer");
+  const char kScriptTemplate[] = R"(
+      let a = document.createElement('a');
+      a.href = $1;
+      document.body.appendChild(a);
+      a.click();
+  )";
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  content::TestNavigationObserver nav_observer(web_contents, 1);
+  ExecuteScriptAsync(web_contents,
+                     content::JsReplace(kScriptTemplate, target_url));
+
+  // Wait for navigation to complete and verify it was successful.
+  nav_observer.WaitForNavigationFinished();
+  EXPECT_TRUE(nav_observer.last_navigation_succeeded());
+  EXPECT_EQ(target_url, nav_observer.last_navigation_url());
+  EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
+
+  // Verify that the Referrer header was not present (in particular, it should
+  // not reveal the identity of the extension).
+  content::WaitForLoadStop(web_contents);
+  EXPECT_EQ("None", content::EvalJs(web_contents, "document.body.innerText"));
+
+  // Verify that the initiator_origin was present and set to the extension.
+  ASSERT_TRUE(nav_observer.last_initiator_origin().has_value());
+  EXPECT_EQ(url::Origin::Create(page_url),
+            nav_observer.last_initiator_origin());
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/user_script_listener.cc b/chrome/browser/extensions/user_script_listener.cc
index 8e948661..3341190d 100644
--- a/chrome/browser/extensions/user_script_listener.cc
+++ b/chrome/browser/extensions/user_script_listener.cc
@@ -12,7 +12,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/notification_service.h"
@@ -20,7 +19,6 @@
 #include "extensions/common/manifest_handlers/content_scripts_handler.h"
 #include "extensions/common/url_pattern.h"
 
-using content::BrowserThread;
 using content::NavigationThrottle;
 using content::ResourceType;
 
@@ -77,8 +75,6 @@
 };
 
 UserScriptListener::UserScriptListener() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
   // Profile manager can be null in unit tests.
   if (g_browser_process->profile_manager()) {
     for (auto* profile :
@@ -90,8 +86,6 @@
   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED,
                  content::NotificationService::AllSources());
 
-  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
-                 content::NotificationService::AllSources());
   registrar_.Add(this,
                  extensions::NOTIFICATION_USER_SCRIPTS_UPDATED,
                  content::NotificationService::AllSources());
@@ -117,7 +111,6 @@
 UserScriptListener::~UserScriptListener() {}
 
 bool UserScriptListener::ShouldDelayRequest(const GURL& url) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Note: we could delay only requests made by the profile who is causing the
   // delay, but it's a little more complicated to associate requests with the
   // right profile. Since this is a rare case, we'll just take the easy way
@@ -150,7 +143,6 @@
 }
 
 void UserScriptListener::CheckIfAllUserScriptsReady() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   bool was_ready = user_scripts_ready_;
 
   user_scripts_ready_ = true;
@@ -165,23 +157,15 @@
 }
 
 void UserScriptListener::UserScriptsReady(content::BrowserContext* context) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(!context->IsOffTheRecord());
 
   profile_data_[context].user_scripts_ready = true;
   CheckIfAllUserScriptsReady();
 }
 
-void UserScriptListener::ProfileDestroyed(content::BrowserContext* context) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  profile_data_.erase(context);
-
-  // We may have deleted the only profile we were waiting on.
-  CheckIfAllUserScriptsReady();
-}
-
 void UserScriptListener::AppendNewURLPatterns(content::BrowserContext* context,
                                               const URLPatterns& new_patterns) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(!context->IsOffTheRecord());
 
   user_scripts_ready_ = false;
 
@@ -194,16 +178,14 @@
 
 void UserScriptListener::ReplaceURLPatterns(content::BrowserContext* context,
                                             const URLPatterns& patterns) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // TODO(estade): enable this check once it no longer fails.
+  // DCHECK_EQ(1U, profile_data_.count(context));
 
-  ProfileData& data = profile_data_[context];
-  data.url_patterns = patterns;
+  profile_data_[context].url_patterns = patterns;
 }
 
 void UserScriptListener::CollectURLPatterns(const Extension* extension,
                                             URLPatterns* patterns) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
   for (const std::unique_ptr<UserScript>& script :
        ContentScriptsInfo::GetContentScripts(extension)) {
     patterns->insert(patterns->end(), script->url_patterns().begin(),
@@ -214,8 +196,6 @@
 void UserScriptListener::Observe(int type,
                                  const content::NotificationSource& source,
                                  const content::NotificationDetails& details) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
   switch (type) {
     case chrome::NOTIFICATION_PROFILE_ADDED: {
       auto* registry =
@@ -224,11 +204,6 @@
       extension_registry_observer_.Add(registry);
       break;
     }
-    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
-      Profile* profile = content::Source<Profile>(source).ptr();
-      ProfileDestroyed(profile);
-      break;
-    }
     case extensions::NOTIFICATION_USER_SCRIPTS_UPDATED: {
       Profile* profile = content::Source<Profile>(source).ptr();
       UserScriptsReady(profile);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 892a8203..46849eb 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1134,6 +1134,11 @@
     "expiry_milestone": 77
   },
   {
+    "name": "enable-cssom-view-scroll-coordinates",
+    "owners": [ "cathiechen@igalia.com", "fwang@igalia.com" ],
+    "expiry_milestone": 83
+  },
+  {
     "name": "enable-cups-printers-ui-overhaul",
     "owners": [ "jimmyxgong" ],
     "expiry_milestone": 79
@@ -2052,11 +2057,6 @@
     "expiry_milestone": 75
   },
   {
-    "name": "enforce-tls13-downgrade",
-    "owners": [ "davidben", "svaldez" ],
-    "expiry_milestone": 82
-  },
-  {
     "name": "enterprise-reporting-in-browser",
     "owners": [ "pastarmovj", "zmin" ],
     "expiry_milestone": 79
@@ -3242,6 +3242,11 @@
     "expiry_milestone": -1
   },
   {
+    "name": "tls13-hardening-for-local-anchors",
+    "owners": [ "davidben", "svaldez" ],
+    "expiry_milestone": 85
+  },
+  {
     "name": "top-chrome-touch-ui",
     "owners": [ "chrome-desktop-ui-sea@google.com" ],
     "expiry_milestone": 81
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 4336b77a..593f6f1b 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -660,14 +660,6 @@
     "Experimental system for using the Desktop PWA framework for running System"
     "Apps (e.g Settings, Discover).";
 
-const char kEnforceTLS13DowngradeName[] = "TLS 1.3 downgrade hardening";
-const char kEnforceTLS13DowngradeDescription[] =
-    "This option enables the TLS 1.3 downgrade hardening mechanism. This "
-    "hardens TLS 1.3 connections while remaining compatible with TLS 1.0 "
-    "through 1.2 connections. Firewalls and proxies that do not function when "
-    "this is enabled do not implement TLS 1.0 through 1.2 correctly or "
-    "securely. They must be fixed by vendors.";
-
 const char kEnableTLS13EarlyDataName[] = "TLS 1.3 Early Data";
 const char kEnableTLS13EarlyDataDescription[] =
     "This option enables TLS 1.3 Early Data, allowing GET requests to be sent "
@@ -708,6 +700,16 @@
     "scroller'. i.e. The one that gets special features like URL bar movement, "
     "overscroll glow, rotation anchoring, etc.";
 
+const char kEnableCSSOMViewScrollCoordinatesName[] =
+    "CSSOM View Scroll Coordinates";
+const char kEnableCSSOMViewScrollCoordinatesDescription[] =
+    "Enables CSSOM View Scroll Coordinates, this affects to box scroll "
+    "coordinates in scrollTop / scrollLeft / scrollTo' when ScrollOrigin isn't "
+    "at the left top corner. i.e. For leftwards overflow direction box "
+    "the X coordinate will start from 0 to negative value. For upwards box the "
+    "Y coordinate will start from 0 to negative value. And for other directions"
+    "(rightwards and downwards) the value will start from 0 to positive";
+
 const char kEnableLitePageServerPreviewsName[] = "Lite Page Server Previews";
 const char kEnableLitePageServerPreviewsDescription[] =
     "Enable showing Lite Page Previews served from a Previews Server."
@@ -2045,6 +2047,16 @@
     "Tint contents composited using GL with a shade of red to help debug and "
     "study overlay support.";
 
+const char kTLS13HardeningForLocalAnchorsName[] =
+    "TLS 1.3 hardening for local anchors";
+const char kTLS13HardeningForLocalAnchorsDescription[] =
+    "This option enables the TLS 1.3 downgrade hardening mechanism for "
+    "connections authenticated by local trust anchors. This improves security "
+    "for connections to TLS-1.3-capable servers while remaining compatible "
+    "with older servers. Firewalls and proxies that do not function when this "
+    "is enabled do not implement TLS 1.2 correctly or securely and must be "
+    "updated.";
+
 const char kTopChromeTouchUiName[] = "Touch UI Layout";
 const char kTopChromeTouchUiDescription[] =
     "Enables touch UI layout in the browser's top chrome.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 06b1e52..48e4631 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -404,9 +404,6 @@
 extern const char kEnableSystemWebAppsName[];
 extern const char kEnableSystemWebAppsDescription[];
 
-extern const char kEnforceTLS13DowngradeName[];
-extern const char kEnforceTLS13DowngradeDescription[];
-
 extern const char kEnableTLS13EarlyDataName[];
 extern const char kEnableTLS13EarlyDataDescription[];
 
@@ -428,6 +425,9 @@
 extern const char kEnableImplicitRootScrollerName[];
 extern const char kEnableImplicitRootScrollerDescription[];
 
+extern const char kEnableCSSOMViewScrollCoordinatesName[];
+extern const char kEnableCSSOMViewScrollCoordinatesDescription[];
+
 extern const char kEnableLitePageServerPreviewsName[];
 extern const char kEnableLitePageServerPreviewsDescription[];
 
@@ -1210,6 +1210,9 @@
 extern const char kTintGlCompositedContentName[];
 extern const char kTintGlCompositedContentDescription[];
 
+extern const char kTLS13HardeningForLocalAnchorsName[];
+extern const char kTLS13HardeningForLocalAnchorsDescription[];
+
 extern const char kTopChromeTouchUiName[];
 extern const char kTopChromeTouchUiDescription[];
 
diff --git a/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc b/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc
index 230be109d..888b4b9 100644
--- a/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc
+++ b/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc
@@ -83,10 +83,14 @@
 }
 
 // Returns the first matching top domain with an edit distance of at most one
-// to |domain_and_registry|.
+// to |domain_and_registry|. This search is done in lexicographic order on the
+// top 500 suitable domains, instead of in order by popularity. This means that
+// the resulting "similar" domain may not be the most popular domain that
+// matches.
 std::string GetSimilarDomainFromTop500(const DomainInfo& navigated_domain) {
   for (const std::string& navigated_skeleton : navigated_domain.skeletons) {
-    for (const char* const top_domain_skeleton : top500_domains::kTop500) {
+    for (const char* const top_domain_skeleton :
+         top500_domains::kTop500EditDistanceSkeletons) {
       if (lookalikes::IsEditDistanceAtMostOne(
               base::UTF8ToUTF16(navigated_skeleton),
               base::UTF8ToUTF16(top_domain_skeleton))) {
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
index db14e1e..3216f7b4 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
@@ -90,9 +90,7 @@
            cast_channel::ChallengeReplyError::CERT_PARSING_FAILED ||
        last_error.challenge_reply_error ==
            cast_channel::ChallengeReplyError::CANNOT_EXTRACT_PUBLIC_KEY) ||
-      (last_error.net_return_value <=
-           net::ERR_CERT_COMMON_NAME_INVALID &&  // CERT_XXX errors
-       last_error.net_return_value > net::ERR_CERT_END) ||
+      net::IsCertificateError(last_error.net_return_value) ||
       last_error.channel_event ==
           cast_channel::ChannelEvent::SSL_SOCKET_CONNECT_FAILED ||
       last_error.channel_event ==
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux.cc b/chrome/browser/notifications/notification_platform_bridge_linux.cc
index f916e4e..24bae810 100644
--- a/chrome/browser/notifications/notification_platform_bridge_linux.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc
@@ -31,7 +31,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/notifications/notification_display_service_impl.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/shell_integration_linux.h"
+#include "chrome/common/channel_info.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -691,8 +691,7 @@
     }
 
     std::unique_ptr<base::Environment> env = base::Environment::Create();
-    base::FilePath desktop_file(
-        shell_integration_linux::GetDesktopName(env.get()));
+    base::FilePath desktop_file(chrome::GetDesktopName(env.get()));
     const char kDesktopFileSuffix[] = ".desktop";
     DCHECK(base::EndsWith(desktop_file.value(), kDesktopFileSuffix,
                           base::CompareCase::SENSITIVE));
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
index 4cf6e7e..229ae68 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
@@ -693,7 +693,7 @@
 }
 
 void OptimizationGuideHintsManager::RegisterOptimizationTypes(
-    std::vector<optimization_guide::proto::OptimizationType>
+    const std::vector<optimization_guide::proto::OptimizationType>&
         optimization_types) {
   bool should_load_new_optimization_filter = false;
   for (const auto optimization_type : optimization_types) {
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
index c77e07b..fa7b9b4 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
@@ -89,7 +89,7 @@
   // Registers the optimization types that have the potential for hints to be
   // called by consumers of the Optimization Guide.
   void RegisterOptimizationTypes(
-      std::vector<optimization_guide::proto::OptimizationType>
+      const std::vector<optimization_guide::proto::OptimizationType>&
           optimization_types);
 
   // Returns whether there have been any optimization types registered.
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
index 49e35c1..9ed594fd 100644
--- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/optimization_guide/optimization_guide_session_statistic.h"
 #include "chrome/browser/optimization_guide/optimization_guide_top_host_provider.h"
 #include "chrome/browser/optimization_guide/optimization_guide_web_contents_observer.h"
+#include "chrome/browser/optimization_guide/prediction/prediction_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
 #include "components/optimization_guide/command_line_top_host_provider.h"
@@ -143,6 +144,8 @@
       database_provider, top_host_provider_.get(),
       content::BrowserContext::GetDefaultStoragePartition(profile)
           ->GetURLLoaderFactoryForBrowserProcess());
+  prediction_manager_ =
+      std::make_unique<optimization_guide::PredictionManager>();
 }
 
 void OptimizationGuideKeyedService::MaybeLoadHintForNavigation(
@@ -155,12 +158,15 @@
   }
 }
 
-void OptimizationGuideKeyedService::RegisterOptimizationTypes(
-    std::vector<optimization_guide::proto::OptimizationType>
-        optimization_types) {
+void OptimizationGuideKeyedService::RegisterOptimizationTypesAndTargets(
+    const std::vector<optimization_guide::proto::OptimizationType>&
+        optimization_types,
+    const std::vector<optimization_guide::proto::OptimizationTarget>&
+        optimization_targets) {
   DCHECK(hints_manager_);
-
+  DCHECK(prediction_manager_);
   hints_manager_->RegisterOptimizationTypes(optimization_types);
+  prediction_manager_->RegisterOptimizationTargets(optimization_targets);
 }
 
 optimization_guide::OptimizationGuideDecision
@@ -198,10 +204,6 @@
 }
 
 void OptimizationGuideKeyedService::UpdateSessionFCP(base::TimeDelta fcp) {
-  // TODO(crbug/1001194): This will be passed to the
-  // OptimizationGuidePredictionManager that will own the FCP session
-  // statistics.
-  if (!session_fcp_)
-    session_fcp_ = std::make_unique<OptimizationGuideSessionStatistic>();
-  session_fcp_->AddSample(static_cast<float>(fcp.InMilliseconds()));
+  if (prediction_manager_)
+    prediction_manager_->UpdateFCPSessionStatistics(fcp);
 }
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.h b/chrome/browser/optimization_guide/optimization_guide_keyed_service.h
index 3a139012..d6abc5f 100644
--- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.h
+++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.h
@@ -31,10 +31,10 @@
 namespace optimization_guide {
 class OptimizationGuideService;
 class TopHostProvider;
+class PredictionManager;
 }  // namespace optimization_guide
 
 class OptimizationGuideHintsManager;
-class OptimizationGuideSessionStatistic;
 
 class OptimizationGuideKeyedService
     : public KeyedService,
@@ -60,6 +60,10 @@
     return top_host_provider_.get();
   }
 
+  optimization_guide::PredictionManager* GetPredictionManager() {
+    return prediction_manager_.get();
+  }
+
   // Prompts the load of the hint for the navigation, if there is at least one
   // optimization type registered and there is a hint available.
   void MaybeLoadHintForNavigation(content::NavigationHandle* navigation_handle);
@@ -68,9 +72,11 @@
   void ClearData();
 
   // optimization_guide::OptimizationGuideDecider implementation:
-  void RegisterOptimizationTypes(
-      std::vector<optimization_guide::proto::OptimizationType>
-          optimization_types) override;
+  void RegisterOptimizationTypesAndTargets(
+      const std::vector<optimization_guide::proto::OptimizationType>&
+          optimization_types,
+      const std::vector<optimization_guide::proto::OptimizationTarget>&
+          optimization_targets) override;
   optimization_guide::OptimizationGuideDecision CanApplyOptimization(
       content::NavigationHandle* navigation_handle,
       optimization_guide::proto::OptimizationTarget optimization_target,
@@ -80,21 +86,18 @@
   // KeyedService implementation:
   void Shutdown() override;
 
-  // Update |session_fcp_| with the provided fcp value.
+  // Updates |prediction_manager_| with the provided fcp value.
   void UpdateSessionFCP(base::TimeDelta fcp);
 
-  OptimizationGuideSessionStatistic* GetSessionFCPForTesting() const {
-    return session_fcp_.get();
-  }
-
  private:
   content::BrowserContext* browser_context_;
 
   // Manages the storing, loading, and fetching of hints.
   std::unique_ptr<OptimizationGuideHintsManager> hints_manager_;
 
-  // The current session's FCP statistics for HTTP/HTTPS navigations.
-  std::unique_ptr<OptimizationGuideSessionStatistic> session_fcp_;
+  // Manages the storing, loading, and evaluating of optimization target
+  // prediction models.
+  std::unique_ptr<optimization_guide::PredictionManager> prediction_manager_;
 
   // The top host provider to use for fetching information for the user's top
   // hosts. Will be null if the user has not consented to this type of browser
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc
index 6661fed..2c656ab5 100644
--- a/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc
@@ -181,7 +181,8 @@
 
   void RegisterWithKeyedService() {
     OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
-        ->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT});
+        ->RegisterOptimizationTypesAndTargets(
+            {optimization_guide::proto::NOSCRIPT}, /*optimization_targets=*/{});
   }
 
   void PushHintsComponentAndWaitForCompletion() {
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager.h b/chrome/browser/optimization_guide/prediction/prediction_manager.h
index d51bb60..55411fa 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager.h
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager.h
@@ -52,6 +52,10 @@
   // Updates |session_fcp_| and |previous_fcp_| with |fcp|.
   void UpdateFCPSessionStatistics(base::TimeDelta fcp);
 
+  OptimizationGuideSessionStatistic* GetFCPSessionStatisticsForTesting() const {
+    return const_cast<OptimizationGuideSessionStatistic*>(&session_fcp_);
+  }
+
   // network::NetworkQualityTracker::EffectiveConnectionTypeObserver
   // implementation:
   void OnEffectiveConnectionTypeChanged(
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc b/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
index 9cd52a6b..130bfc3 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/optimization_guide/optimization_guide_session_statistic.h"
+#include "chrome/browser/optimization_guide/prediction/prediction_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -50,7 +51,9 @@
 
   void RegisterWithKeyedService() {
     OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
-        ->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT});
+        ->RegisterOptimizationTypesAndTargets(
+            {optimization_guide::proto::NOSCRIPT},
+            {optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD});
   }
 
   std::unique_ptr<page_load_metrics::PageLoadMetricsTestWaiter>
@@ -84,8 +87,9 @@
   ui_test_utils::NavigateToURL(browser(), https_url_with_content());
   waiter->Wait();
 
-  OptimizationGuideSessionStatistic* session_fcp =
-      keyed_service->GetSessionFCPForTesting();
+  const OptimizationGuideSessionStatistic* session_fcp =
+      keyed_service->GetPredictionManager()
+          ->GetFCPSessionStatisticsForTesting();
   EXPECT_TRUE(session_fcp);
   EXPECT_EQ(1u, session_fcp->GetNumberOfSamples());
 }
@@ -102,8 +106,9 @@
   ui_test_utils::NavigateToURL(browser(), https_url_with_content());
   waiter->Wait();
 
-  OptimizationGuideSessionStatistic* session_fcp =
-      keyed_service->GetSessionFCPForTesting();
+  const OptimizationGuideSessionStatistic* session_fcp =
+      keyed_service->GetPredictionManager()
+          ->GetFCPSessionStatisticsForTesting();
   float current_mean = session_fcp->GetMean();
 
   waiter = CreatePageLoadMetricsTestWaiter();
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
index afc7eb0..425e785 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -849,20 +849,20 @@
                   std::min(ad_frame_data.frame_size().width(),
                            ad_frame_data.frame_size().height()));
 
-    ADS_HISTOGRAM("Bytes.AdFrames.PerFrame.Total", PAGE_BYTES_HISTOGRAM,
+    ADS_HISTOGRAM("Bytes.AdFrames.PerFrame.Total2", PAGE_BYTES_HISTOGRAM,
                   visibility, ad_frame_data.bytes());
     ADS_HISTOGRAM("Bytes.AdFrames.PerFrame.Network", PAGE_BYTES_HISTOGRAM,
                   visibility, ad_frame_data.network_bytes());
-    ADS_HISTOGRAM("Bytes.AdFrames.PerFrame.SameOrigin", PAGE_BYTES_HISTOGRAM,
+    ADS_HISTOGRAM("Bytes.AdFrames.PerFrame.SameOrigin2", PAGE_BYTES_HISTOGRAM,
                   visibility, ad_frame_data.same_origin_bytes());
     if (ad_frame_data.bytes() > 0) {
       ADS_HISTOGRAM(
-          "Bytes.AdFrames.PerFrame.PercentNetwork", UMA_HISTOGRAM_PERCENTAGE,
+          "Bytes.AdFrames.PerFrame.PercentNetwork2", UMA_HISTOGRAM_PERCENTAGE,
           visibility,
           ad_frame_data.network_bytes() * 100 / ad_frame_data.bytes());
       ADS_HISTOGRAM(
-          "Bytes.AdFrames.PerFrame.PercentSameOrigin", UMA_HISTOGRAM_PERCENTAGE,
-          visibility,
+          "Bytes.AdFrames.PerFrame.PercentSameOrigin2",
+          UMA_HISTOGRAM_PERCENTAGE, visibility,
           ad_frame_data.same_origin_bytes() * 100 / ad_frame_data.bytes());
     }
     ADS_HISTOGRAM("FrameCounts.AdFrames.PerFrame.OriginStatus",
@@ -894,18 +894,19 @@
   if (aggregate_ad_info.num_frames == 0)
     return;
 
-  ADS_HISTOGRAM("Bytes.NonAdFrames.Aggregate.Total", PAGE_BYTES_HISTOGRAM,
+  ADS_HISTOGRAM("Bytes.NonAdFrames.Aggregate.Total2", PAGE_BYTES_HISTOGRAM,
                 visibility,
                 aggregate_frame_data_->bytes() - aggregate_ad_info.bytes);
 
-  ADS_HISTOGRAM("Bytes.FullPage.Total", PAGE_BYTES_HISTOGRAM, visibility,
+  ADS_HISTOGRAM("Bytes.FullPage.Total2", PAGE_BYTES_HISTOGRAM, visibility,
                 aggregate_frame_data_->bytes());
   ADS_HISTOGRAM("Bytes.FullPage.Network", PAGE_BYTES_HISTOGRAM, visibility,
                 aggregate_frame_data_->network_bytes());
 
   if (aggregate_frame_data_->bytes()) {
     ADS_HISTOGRAM(
-        "Bytes.FullPage.Total.PercentAds", UMA_HISTOGRAM_PERCENTAGE, visibility,
+        "Bytes.FullPage.Total.PercentAds2", UMA_HISTOGRAM_PERCENTAGE,
+        visibility,
         aggregate_ad_info.bytes * 100 / aggregate_frame_data_->bytes());
   }
   if (aggregate_frame_data_->network_bytes()) {
@@ -915,14 +916,14 @@
                       aggregate_frame_data_->network_bytes());
   }
 
-  ADS_HISTOGRAM("Bytes.AdFrames.Aggregate.Total", PAGE_BYTES_HISTOGRAM,
+  ADS_HISTOGRAM("Bytes.AdFrames.Aggregate.Total2", PAGE_BYTES_HISTOGRAM,
                 visibility, aggregate_ad_info.bytes);
   ADS_HISTOGRAM("Bytes.AdFrames.Aggregate.Network", PAGE_BYTES_HISTOGRAM,
                 visibility, aggregate_ad_info.network_bytes);
 
   if (aggregate_ad_info.bytes) {
     ADS_HISTOGRAM(
-        "Bytes.AdFrames.Aggregate.PercentNetwork", UMA_HISTOGRAM_PERCENTAGE,
+        "Bytes.AdFrames.Aggregate.PercentNetwork2", UMA_HISTOGRAM_PERCENTAGE,
         visibility,
         aggregate_ad_info.network_bytes * 100 / aggregate_ad_info.bytes);
   }
@@ -931,21 +932,21 @@
   // as these numbers do not change for different visibility types.
   if (visibility != FrameData::FrameVisibility::kAnyVisibility)
     return;
-  ADS_HISTOGRAM("Bytes.FullPage.SameOrigin", PAGE_BYTES_HISTOGRAM, visibility,
+  ADS_HISTOGRAM("Bytes.FullPage.SameOrigin2", PAGE_BYTES_HISTOGRAM, visibility,
                 aggregate_frame_data_->same_origin_bytes());
   if (aggregate_frame_data_->bytes()) {
-    ADS_HISTOGRAM("Bytes.FullPage.PercentSameOrigin", UMA_HISTOGRAM_PERCENTAGE,
+    ADS_HISTOGRAM("Bytes.FullPage.PercentSameOrigin2", UMA_HISTOGRAM_PERCENTAGE,
                   visibility,
                   aggregate_frame_data_->same_origin_bytes() * 100 /
                       aggregate_frame_data_->bytes());
   }
   ADS_HISTOGRAM("Bytes.MainFrame.Network", PAGE_BYTES_HISTOGRAM, visibility,
                 main_frame_data_->network_bytes());
-  ADS_HISTOGRAM("Bytes.MainFrame.Total", PAGE_BYTES_HISTOGRAM, visibility,
+  ADS_HISTOGRAM("Bytes.MainFrame.Total2", PAGE_BYTES_HISTOGRAM, visibility,
                 main_frame_data_->bytes());
   ADS_HISTOGRAM("Bytes.MainFrame.Ads.Network", PAGE_BYTES_HISTOGRAM, visibility,
                 main_frame_data_->ad_network_bytes());
-  ADS_HISTOGRAM("Bytes.MainFrame.Ads.Total", PAGE_BYTES_HISTOGRAM, visibility,
+  ADS_HISTOGRAM("Bytes.MainFrame.Ads.Total2", PAGE_BYTES_HISTOGRAM, visibility,
                 main_frame_data_->ad_bytes());
 }
 
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
index b5e804b..826f0b6 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -296,7 +296,8 @@
   histogram_tester.ExpectUniqueSample(
       "PageLoad.Clients.Ads.FrameCounts.AdFrames.Total", 1, 1);
   histogram_tester.ExpectUniqueSample(
-      "PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate.Total", 0 /* < 1 KB */, 1);
+      "PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate.Total2", 0 /* < 1 KB */,
+      1);
   auto entries =
       ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
   EXPECT_EQ(1u, entries.size());
@@ -371,11 +372,11 @@
   waiter->Wait();
   ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
   histogram_tester.ExpectTotalCount(
-      "PageLoad.Clients.Ads.Visible.Bytes.AdFrames.PerFrame.Total", 1);
+      "PageLoad.Clients.Ads.Visible.Bytes.AdFrames.PerFrame.Total2", 1);
   histogram_tester.ExpectTotalCount(
-      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.Total", 1);
+      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.Total2", 1);
   histogram_tester.ExpectTotalCount(
-      "PageLoad.Clients.Ads.NonVisible.Bytes.AdFrames.PerFrame.Total", 0);
+      "PageLoad.Clients.Ads.NonVisible.Bytes.AdFrames.PerFrame.Total2", 0);
   auto entries =
       ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
   EXPECT_EQ(1u, entries.size());
@@ -397,11 +398,11 @@
   // Navigate away to force the histogram recording.
   ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
   histogram_tester.ExpectTotalCount(
-      "PageLoad.Clients.Ads.NonVisible.Bytes.AdFrames.PerFrame.Total", 1);
+      "PageLoad.Clients.Ads.NonVisible.Bytes.AdFrames.PerFrame.Total2", 1);
   histogram_tester.ExpectTotalCount(
-      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.Total", 1);
+      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.Total2", 1);
   histogram_tester.ExpectTotalCount(
-      "PageLoad.Clients.Ads.Visible.Bytes.AdFrames.PerFrame.Total", 0);
+      "PageLoad.Clients.Ads.Visible.Bytes.AdFrames.PerFrame.Total2", 0);
   auto entries =
       ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
   EXPECT_EQ(1u, entries.size());
@@ -534,17 +535,18 @@
 
   // Verify that iframe e is only same origin.
   histogram_tester.ExpectBucketCount(
-      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.PercentSameOrigin", 100, 1);
+      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.PercentSameOrigin2", 100,
+      1);
 
   // Verify that iframe b counts subframes as cross origin and a nested same
   // origin subframe as same origin.
   histogram_tester.ExpectBucketCount(
-      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.PercentSameOrigin", 50, 1);
+      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.PercentSameOrigin2", 50, 1);
 
   // Verify that all iframe are treated as cross-origin to the page. Only 1/8 of
   // resources are on origin a.com.
   histogram_tester.ExpectBucketCount(
-      "PageLoad.Clients.Ads.Bytes.FullPage.PercentSameOrigin", 12.5, 1);
+      "PageLoad.Clients.Ads.Bytes.FullPage.PercentSameOrigin2", 12.5, 1);
 }
 
 IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
@@ -807,12 +809,12 @@
   histogram_tester.ExpectBucketCount(
       "PageLoad.Clients.Ads.Resources.Bytes.Ads2", 4, 1);
   histogram_tester.ExpectBucketCount(
-      "PageLoad.Clients.Ads.Bytes.MainFrame.Ads.Total", 1, 1);
+      "PageLoad.Clients.Ads.Bytes.MainFrame.Ads.Total2", 1, 1);
 
   // The main frame should have 2 KB of resources, 1KB from the main resource
   // and one from the ad script in the main frame.
   histogram_tester.ExpectBucketCount(
-      "PageLoad.Clients.Ads.Bytes.MainFrame.Total", 2, 1);
+      "PageLoad.Clients.Ads.Bytes.MainFrame.Total2", 2, 1);
 }
 
 IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverResourceBrowserTest,
@@ -859,11 +861,11 @@
   histogram_tester.ExpectBucketCount(
       "PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate.Network", 2, 1);
   histogram_tester.ExpectBucketCount(
-      "PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate.Total", 2, 1);
+      "PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate.Total2", 2, 1);
   histogram_tester.ExpectBucketCount(
       "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.Network", 2, 1);
   histogram_tester.ExpectBucketCount(
-      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.Total", 2, 1);
+      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.Total2", 2, 1);
   auto entries =
       ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
   EXPECT_EQ(1u, entries.size());
@@ -871,7 +873,7 @@
       entries.front(), ukm::builders::AdFrameLoad::kLoading_NetworkBytesName,
       ukm::GetExponentialBucketMinForBytes(2048));
   ukm_recorder.ExpectEntryMetric(
-      entries.front(), ukm::builders::AdFrameLoad::kLoading_CacheBytesName, 0);
+      entries.front(), ukm::builders::AdFrameLoad::kLoading_CacheBytes2Name, 0);
 }
 
 // Verifies that the frame is navigated to the intervention page when a
@@ -1291,7 +1293,7 @@
       ukm_recorder.GetEntriesByName(ukm::builders::AdFrameLoad::kEntryName);
   EXPECT_EQ(0u, entries.size());
   histogram_tester.ExpectTotalCount(
-      "PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate.Total", 0);
+      "PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate.Total2", 0);
   histogram_tester.ExpectTotalCount(
       "PageLoad.Clients.Ads.FrameCounts.AdFrames.Total", 0);
 }
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
index 275c833..feda6ed 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -73,7 +73,7 @@
   }
 };
 
-enum class ResourceCached { NOT_CACHED = false, CACHED = true };
+enum class ResourceCached { kNotCached = 0, kCachedHttp, kCachedMemory };
 enum class FrameType { AD = 0, NON_AD };
 
 const char kAdUrl[] = "https://ads.com/ad/disallowed.html";
@@ -208,7 +208,7 @@
 
   for (const auto& total_bytes_and_count : frames_with_total_byte_count) {
     histograms.ExpectBucketCount(
-        SuffixedHistogram("Bytes.AdFrames.PerFrame.Total"),
+        SuffixedHistogram("Bytes.AdFrames.PerFrame.Total2"),
         total_bytes_and_count.first, total_bytes_and_count.second);
   }
   for (const auto& network_bytes_and_count : frames_with_network_byte_count) {
@@ -219,33 +219,33 @@
   for (const auto& percent_network_and_count :
        frames_with_percent_network_count) {
     histograms.ExpectBucketCount(
-        SuffixedHistogram("Bytes.AdFrames.PerFrame.PercentNetwork"),
+        SuffixedHistogram("Bytes.AdFrames.PerFrame.PercentNetwork2"),
         percent_network_and_count.first, percent_network_and_count.second);
   }
 
   histograms.ExpectUniqueSample(
-      SuffixedHistogram("Bytes.AdFrames.Aggregate.Total"), total_ad_kb, 1);
+      SuffixedHistogram("Bytes.AdFrames.Aggregate.Total2"), total_ad_kb, 1);
   histograms.ExpectUniqueSample(
       SuffixedHistogram("Bytes.AdFrames.Aggregate.Network"),
       total_ad_uncached_kb, 1);
   histograms.ExpectUniqueSample(
-      SuffixedHistogram("Bytes.FullPage.Total"),
+      SuffixedHistogram("Bytes.FullPage.Total2"),
       non_ad_cached_kb + non_ad_uncached_kb + total_ad_kb, 1);
   histograms.ExpectUniqueSample(SuffixedHistogram("Bytes.FullPage.Network"),
                                 non_ad_uncached_kb + total_ad_uncached_kb, 1);
   histograms.ExpectUniqueSample(
-      SuffixedHistogram("Bytes.NonAdFrames.Aggregate.Total"),
+      SuffixedHistogram("Bytes.NonAdFrames.Aggregate.Total2"),
       non_ad_cached_kb + non_ad_uncached_kb, 1);
   if (total_ad_kb + non_ad_cached_kb + non_ad_uncached_kb > 0) {
     histograms.ExpectUniqueSample(
-        SuffixedHistogram("Bytes.FullPage.Total.PercentAds"),
+        SuffixedHistogram("Bytes.FullPage.Total.PercentAds2"),
         (total_ad_kb * 100) /
             (total_ad_kb + non_ad_cached_kb + non_ad_uncached_kb),
         1);
   }
   if (total_ad_kb > 0) {
     histograms.ExpectUniqueSample(
-        SuffixedHistogram("Bytes.AdFrames.Aggregate.PercentNetwork"),
+        SuffixedHistogram("Bytes.AdFrames.Aggregate.PercentNetwork2"),
         ((total_ad_uncached_kb * 100) / total_ad_kb), 1);
   }
   if (total_ad_uncached_kb + non_ad_uncached_kb > 0) {
@@ -267,7 +267,7 @@
     int matching_entries = 0;
     for (auto const* entry : entries) {
       int64_t entry_cache_bytes = *ukm_recorder.GetEntryMetric(
-          entry, ukm::builders::AdFrameLoad::kLoading_CacheBytesName);
+          entry, ukm::builders::AdFrameLoad::kLoading_CacheBytes2Name);
       int64_t entry_network_bytes = *ukm_recorder.GetEntryMetric(
           entry, ukm::builders::AdFrameLoad::kLoading_NetworkBytesName);
       if (entry_cache_bytes ==
@@ -391,9 +391,17 @@
     resource->encoded_body_length = resource_size_in_kbyte << 10;
     resource->reported_as_ad_resource = is_ad_resource;
     resource->is_complete = true;
-    resource->cache_type = (resource_cached == ResourceCached::NOT_CACHED)
-                               ? page_load_metrics::mojom::CacheType::kNotCached
-                               : page_load_metrics::mojom::CacheType::kHttp;
+    switch (resource_cached) {
+      case ResourceCached::kNotCached:
+        resource->cache_type = page_load_metrics::mojom::CacheType::kNotCached;
+        break;
+      case ResourceCached::kCachedHttp:
+        resource->cache_type = page_load_metrics::mojom::CacheType::kHttp;
+        break;
+      case ResourceCached::kCachedMemory:
+        resource->cache_type = page_load_metrics::mojom::CacheType::kMemory;
+        break;
+    }
     resource->mime_type = mime_type;
     resource->is_primary_frame_resource = true;
     resource->is_main_frame_resource =
@@ -497,9 +505,9 @@
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
   RenderFrameHost* frame1 = CreateAndNavigateSubFrame(kNonAdUrl, main_frame);
   RenderFrameHost* frame2 = CreateAndNavigateSubFrame(kNonAdUrl, main_frame);
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
-  ResourceDataUpdate(frame1, ResourceCached::NOT_CACHED, 10);
-  ResourceDataUpdate(frame2, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(frame1, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(frame2, ResourceCached::kNotCached, 10);
 
   // Navigate again to trigger histograms.
   NavigateFrame(kNonAdUrl, main_frame);
@@ -517,9 +525,9 @@
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
   RenderFrameHost* frame1 = CreateAndNavigateSubFrame(kNonAdUrl, main_frame);
   RenderFrameHost* frame2 = CreateAndNavigateSubFrame(kAdUrl, main_frame);
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
-  ResourceDataUpdate(frame1, ResourceCached::NOT_CACHED, 10);
-  ResourceDataUpdate(frame2, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(frame1, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(frame2, ResourceCached::kNotCached, 10);
 
   // Navigate again to trigger histograms.
   NavigateFrame(kNonAdUrl, main_frame);
@@ -531,19 +539,19 @@
 TEST_F(AdsPageLoadMetricsObserverTest, AdFrameMimeTypeBytes) {
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
   ResourceDataUpdate(
-      ad_frame, ResourceCached::NOT_CACHED, 10 /* resource_size_in_kbyte */,
+      ad_frame, ResourceCached::kNotCached, 10 /* resource_size_in_kbyte */,
       "application/javascript" /* mime_type */, true /* is_ad_resource */);
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      20 /* resource_size_in_kbyte */,
                      "image/png" /* mime_type */, true /* is_ad_resource */);
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      30 /* resource_size_in_kbyte */,
                      "video/webm" /* mime_type */, true /* is_ad_resource */);
 
   // Cached resource not counted.
-  ResourceDataUpdate(ad_frame, ResourceCached::CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kCachedHttp,
                      40 /* resource_size_in_kbyte */,
                      "video/webm" /* mime_type */, true /* is_ad_resource */);
 
@@ -565,7 +573,7 @@
       entries.front(), ukm::builders::AdFrameLoad::kLoading_NetworkBytesName,
       ukm::GetExponentialBucketMinForBytes(60 * 1024));
   test_ukm_recorder().ExpectEntryMetric(
-      entries.front(), ukm::builders::AdFrameLoad::kLoading_CacheBytesName,
+      entries.front(), ukm::builders::AdFrameLoad::kLoading_CacheBytes2Name,
       ukm::GetExponentialBucketMinForBytes(40 * 1024));
   test_ukm_recorder().ExpectEntryMetric(
       entries.front(), ukm::builders::AdFrameLoad::kLoading_NumResourcesName,
@@ -575,14 +583,14 @@
 TEST_F(AdsPageLoadMetricsObserverTest, ResourceBeforeAdFrameCommits) {
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
 
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
 
   // Create subframe and load resource before commit.
   RenderFrameHost* subframe =
       RenderFrameHostTester::For(main_frame)->AppendChild("foo");
   auto navigation_simulator =
       NavigationSimulator::CreateRendererInitiated(GURL(kAdUrl), subframe);
-  ResourceDataUpdate(subframe, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(subframe, ResourceCached::kNotCached, 10);
   navigation_simulator->Commit();
 
   // Navigate again to trigger histograms.
@@ -609,10 +617,10 @@
     RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
     RenderFrameHost* ad_sub_frame =
         CreateAndNavigateSubFrame(kAdUrl, main_frame);
-    ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
-    ResourceDataUpdate(ad_sub_frame, ResourceCached::NOT_CACHED, 10);
+    ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
+    ResourceDataUpdate(ad_sub_frame, ResourceCached::kNotCached, 10);
     ResourceDataUpdate(CreateAndNavigateSubFrame(kAdUrl, ad_sub_frame),
-                       ResourceCached::NOT_CACHED, 10);
+                       ResourceCached::kNotCached, 10);
     // Trigger histograms by navigating away, then test them.
     NavigateFrame(kAdUrl, main_frame);
     histograms.ExpectUniqueSample(kCrossOriginHistogramId,
@@ -631,11 +639,11 @@
     base::HistogramTester histograms;
     ukm::TestAutoSetUkmRecorder ukm_recorder;
     RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-    ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
+    ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
     ResourceDataUpdate(CreateAndNavigateSubFrame(kAdUrl, main_frame),
-                       ResourceCached::NOT_CACHED, 10);
+                       ResourceCached::kNotCached, 10);
     ResourceDataUpdate(CreateAndNavigateSubFrame(kNonAdUrl, main_frame),
-                       ResourceCached::NOT_CACHED, 10);
+                       ResourceCached::kNotCached, 10);
     // Trigger histograms by navigating away, then test them.
     NavigateFrame(kAdUrl, main_frame);
     histograms.ExpectUniqueSample(kCrossOriginHistogramId,
@@ -655,9 +663,9 @@
     base::HistogramTester histograms;
     ukm::TestAutoSetUkmRecorder ukm_recorder;
     RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrlSameOrigin);
-    ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
+    ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
     ResourceDataUpdate(CreateAndNavigateSubFrame(kAdUrl, main_frame),
-                       ResourceCached::NOT_CACHED, 10);
+                       ResourceCached::kNotCached, 10);
     // Trigger histograms by navigating away, then test them.
     NavigateFrame(kAdUrl, main_frame);
     histograms.ExpectUniqueSample(kCrossOriginHistogramId,
@@ -675,14 +683,14 @@
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   // Navigate the ad frame again.
   ad_frame = NavigateFrame(kNonAdUrl, ad_frame);
 
   // In total, 30KB for entire page and 20 in one ad frame.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   // Navigate again to trigger histograms.
   NavigateFrame(kNonAdUrl, main_frame);
@@ -702,13 +710,13 @@
   RenderFrameHost* sub_frame_child_ad =
       CreateAndNavigateSubFrame(kAdUrl, sub_frame);
 
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
-  ResourceDataUpdate(sub_frame, ResourceCached::NOT_CACHED, 10);
-  ResourceDataUpdate(sub_frame_child_ad, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(sub_frame, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(sub_frame_child_ad, ResourceCached::kNotCached, 10);
 
   // Navigate the subframe again, this time it's an ad.
   sub_frame = NavigateFrame(kAdUrl, sub_frame);
-  ResourceDataUpdate(sub_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(sub_frame, ResourceCached::kNotCached, 10);
 
   // In total, 40KB was loaded for the entire page and 20KB from ad
   // frames (the original child ad frame and the renavigated frame which
@@ -724,7 +732,7 @@
 TEST_F(AdsPageLoadMetricsObserverTest, CountAbortedNavigation) {
   // If the first navigation in a frame is aborted, keep track of its bytes.
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
 
   // Create an ad subframe that aborts before committing.
   RenderFrameHost* subframe_ad =
@@ -739,8 +747,8 @@
   // Load resources for the aborted frame (e.g., simulate the navigation
   // aborting due to a doc.write during provisional navigation). They should
   // be counted.
-  ResourceDataUpdate(subframe_ad, ResourceCached::NOT_CACHED, 10);
-  ResourceDataUpdate(subframe_ad, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(subframe_ad, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(subframe_ad, ResourceCached::kNotCached, 10);
 
   // Navigate again to trigger histograms.
   NavigateFrame(kNonAdUrl, main_frame);
@@ -751,11 +759,11 @@
 
 TEST_F(AdsPageLoadMetricsObserverTest, CountAbortedSecondNavigationForFrame) {
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
 
   // Sub frame that is not an ad.
   RenderFrameHost* sub_frame = CreateAndNavigateSubFrame(kNonAdUrl, main_frame);
-  ResourceDataUpdate(sub_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(sub_frame, ResourceCached::kNotCached, 10);
 
   // Now navigate (and abort) the subframe to an ad.
   auto navigation_simulator =
@@ -768,8 +776,8 @@
   // Load resources for the aborted frame (e.g., simulate the navigation
   // aborting due to a doc.write during provisional navigation). Since the
   // frame attempted to load an ad, the frame is tagged forever as an ad.
-  ResourceDataUpdate(sub_frame, ResourceCached::NOT_CACHED, 10);
-  ResourceDataUpdate(sub_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(sub_frame, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(sub_frame, ResourceCached::kNotCached, 10);
 
   // Navigate again to trigger histograms.
   NavigateFrame(kNonAdUrl, main_frame);
@@ -781,7 +789,7 @@
 TEST_F(AdsPageLoadMetricsObserverTest, TwoResourceLoadsBeforeCommit) {
   // Main frame.
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
 
   // Now open a subframe and have its resource load before notification of
   // navigation finishing.
@@ -789,7 +797,7 @@
       RenderFrameHostTester::For(main_frame)->AppendChild("foo");
   auto navigation_simulator =
       NavigationSimulator::CreateRendererInitiated(GURL(kAdUrl), subframe_ad);
-  ResourceDataUpdate(subframe_ad, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(subframe_ad, ResourceCached::kNotCached, 10);
 
   // The sub-frame renavigates before it commits.
   navigation_simulator->Start();
@@ -798,7 +806,7 @@
 
   // Renavigate the subframe to a successful commit. But again, the resource
   // loads before the observer sees the finished navigation.
-  ResourceDataUpdate(subframe_ad, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(subframe_ad, ResourceCached::kNotCached, 10);
   NavigateFrame(kNonAdUrl, subframe_ad);
 
   // Navigate again to trigger histograms.
@@ -816,7 +824,7 @@
   navigation_simulator->Commit();
 
   ResourceDataUpdate(navigation_simulator->GetFinalRenderFrameHost(),
-                     ResourceCached::NOT_CACHED, 10);
+                     ResourceCached::kNotCached, 10);
 
   NavigateMainFrame(kNonAdUrl);
 
@@ -877,7 +885,7 @@
   ConfigureAsSubresourceFilterOnlyURL(GURL(kNonAdUrl));
   NavigateMainFrame(kNonAdUrl);
 
-  ResourceDataUpdate(main_rfh(), ResourceCached::NOT_CACHED, 10,
+  ResourceDataUpdate(main_rfh(), ResourceCached::kNotCached, 10,
                      "" /* mime_type */, false /* is_ad_resource */);
 
   RenderFrameHost* subframe =
@@ -885,7 +893,7 @@
   std::unique_ptr<NavigationSimulator> simulator =
       NavigationSimulator::CreateRendererInitiated(GURL(kDefaultDisallowedUrl),
                                                    subframe);
-  ResourceDataUpdate(subframe, ResourceCached::NOT_CACHED, 10,
+  ResourceDataUpdate(subframe, ResourceCached::kNotCached, 10,
                      "" /* mime_type */, true /* is_ad_resource */);
   simulator->Commit();
 
@@ -905,25 +913,25 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
   RenderFrameHost* child_ad_frame = CreateAndNavigateSubFrame(kAdUrl, ad_frame);
 
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
 
   // Add some data to the ad frame so it gets reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
-  ResourceDataUpdate(child_ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(child_ad_frame, ResourceCached::kNotCached, 10);
 
   // Just delete the child frame this time.
   content::RenderFrameHostTester::For(child_ad_frame)->Detach();
 
   // Verify per-frame histograms not recorded.
   histogram_tester().ExpectTotalCount(
-      SuffixedHistogram("Bytes.AdFrames.PerFrame.Total"), 0);
+      SuffixedHistogram("Bytes.AdFrames.PerFrame.Total2"), 0);
 
   // Delete the root ad frame.
   content::RenderFrameHostTester::For(ad_frame)->Detach();
 
   // Verify per-frame histograms are recorded.
   histogram_tester().ExpectUniqueSample(
-      SuffixedHistogram("Bytes.AdFrames.PerFrame.Total"), 20, 1);
+      SuffixedHistogram("Bytes.AdFrames.PerFrame.Total2"), 20, 1);
 
   // Verify page totals not reported yet.
   histogram_tester().ExpectTotalCount(
@@ -943,7 +951,7 @@
   RenderFrameHost* vanilla_frame =
       CreateAndNavigateSubFrame(kNonAdUrl, main_frame);
 
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
 
   content::RenderFrameHostTester::For(vanilla_frame)->Detach();
 
@@ -954,25 +962,25 @@
 TEST_F(AdsPageLoadMetricsObserverTest, MainFrameAdBytesRecorded) {
   NavigateMainFrame(kNonAdUrl);
 
-  ResourceDataUpdate(main_rfh(), ResourceCached::NOT_CACHED, 10,
+  ResourceDataUpdate(main_rfh(), ResourceCached::kNotCached, 10,
                      "" /* mime_type */, true /* is_ad_resource */);
-  ResourceDataUpdate(main_rfh(), ResourceCached::CACHED, 10, "" /* mime_type */,
-                     true /* is_ad_resource */);
+  ResourceDataUpdate(main_rfh(), ResourceCached::kCachedHttp, 10,
+                     "" /* mime_type */, true /* is_ad_resource */);
 
   RenderFrameHost* subframe =
       RenderFrameHostTester::For(main_rfh())->AppendChild("foo");
   std::unique_ptr<NavigationSimulator> simulator =
       NavigationSimulator::CreateRendererInitiated(GURL(kDefaultDisallowedUrl),
                                                    subframe);
-  ResourceDataUpdate(subframe, ResourceCached::NOT_CACHED, 10,
+  ResourceDataUpdate(subframe, ResourceCached::kNotCached, 10,
                      "" /* mime_type */, true /* is_ad_resource */);
-  ResourceDataUpdate(subframe, ResourceCached::CACHED, 10, "" /* mime_type */,
-                     true /* is_ad_resource */);
+  ResourceDataUpdate(subframe, ResourceCached::kCachedHttp, 10,
+                     "" /* mime_type */, true /* is_ad_resource */);
   simulator->Commit();
 
   NavigateMainFrame(kNonAdUrl);
   histogram_tester().ExpectUniqueSample(
-      SuffixedHistogram("Bytes.MainFrame.Ads.Total"), 20, 1);
+      SuffixedHistogram("Bytes.MainFrame.Ads.Total2"), 20, 1);
   histogram_tester().ExpectUniqueSample(
       SuffixedHistogram("Bytes.MainFrame.Ads.Network"), 10, 1);
 
@@ -981,6 +989,22 @@
       SuffixedHistogram("Resources.Bytes.Ads2"), 20, 1);
 }
 
+// Tests that memory cache ad bytes are recorded correctly.
+TEST_F(AdsPageLoadMetricsObserverTest, MemoryCacheAdBytesRecorded) {
+  RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
+  RenderFrameHost* frame1 = CreateAndNavigateSubFrame(kNonAdUrl, main_frame);
+  RenderFrameHost* frame2 = CreateAndNavigateSubFrame(kAdUrl, main_frame);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
+  ResourceDataUpdate(frame1, ResourceCached::kCachedMemory, 10);
+  ResourceDataUpdate(frame2, ResourceCached::kCachedMemory, 10);
+
+  // Navigate again to trigger histograms.
+  NavigateFrame(kNonAdUrl, main_frame);
+
+  TestHistograms(histogram_tester(), test_ukm_recorder(), {{10, 0}},
+                 10 /* non_ad_cached_kb */, 10 /* non_ad_uncached_kb */);
+}
+
 // UKM metrics for ad page load are recorded correctly.
 TEST_F(AdsPageLoadMetricsObserverTest, AdPageLoadUKM) {
   ukm::TestAutoSetUkmRecorder ukm_recorder;
@@ -995,12 +1019,12 @@
   PopulateRequiredTimingFields(&timing);
   TimingUpdate(timing);
   ResourceDataUpdate(
-      main_rfh(), ResourceCached::NOT_CACHED, 10 /* resource_size_in_kbyte */,
+      main_rfh(), ResourceCached::kNotCached, 10 /* resource_size_in_kbyte */,
       "application/javascript" /* mime_type */, false /* is_ad_resource */);
   ResourceDataUpdate(
-      main_rfh(), ResourceCached::NOT_CACHED, 10 /* resource_size_in_kbyte */,
+      main_rfh(), ResourceCached::kNotCached, 10 /* resource_size_in_kbyte */,
       "application/javascript" /* mime_type */, true /* is_ad_resource */);
-  ResourceDataUpdate(main_rfh(), ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(main_rfh(), ResourceCached::kNotCached,
                      10 /* resource_size_in_kbyte */,
                      "video/webm" /* mime_type */, true /* is_ad_resource */);
 
@@ -1055,7 +1079,7 @@
   RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
-  ResourceDataUpdate(main_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(main_frame, ResourceCached::kNotCached, 10);
 
   // Use CPU but maintain zero bytes in the ad frame
   OnCpuTimingUpdate(ad_frame, base::TimeDelta::FromMilliseconds(1000));
@@ -1076,7 +1100,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add some data to the ad frame so it gets reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   // Perform some updates on ad and non-ad frames. Usage 1%.
   OnCpuTimingUpdate(ad_frame, base::TimeDelta::FromMilliseconds(500));
@@ -1130,7 +1154,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add some data to the ad frame so it gets reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   // Perform some updates on ad and non-ad frames. Usage 1%.
   OnCpuTimingUpdate(ad_frame, base::TimeDelta::FromMilliseconds(500));
@@ -1187,7 +1211,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add some data to the ad frame so it gets reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   // Perform some updates on ad and non-ad frames.
   OnCpuTimingUpdate(ad_frame, base::TimeDelta::FromMilliseconds(500));
@@ -1241,7 +1265,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add some data to the ad frame so it get reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   // Perform some updates on ad and non-ad frames.
   OnCpuTimingUpdate(ad_frame, base::TimeDelta::FromMilliseconds(500));
@@ -1298,7 +1322,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add some data to the ad frame so it get reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   // Perform some updates on ad and non-ad frames.
   OnCpuTimingUpdate(ad_frame, base::TimeDelta::FromMilliseconds(500));
@@ -1361,7 +1385,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add some data to the ad frame so it get reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   // Set the frame as backgrounded, so all updates below shouldn't report.
   OnHidden();
@@ -1420,7 +1444,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add some data to the ad frame so it get reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   // Perform some updates on ad and non-ad frames.
   OnCpuTimingUpdate(ad_frame, base::TimeDelta::FromMilliseconds(500));
@@ -1456,7 +1480,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add some data to the ad frame so it get reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   // Perform some updates on ad and non-ad frames.
   OnCpuTimingUpdate(ad_frame, base::TimeDelta::FromMilliseconds(500));
@@ -1504,7 +1528,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Load bytes in frame to record ukm event.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 10);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 10);
 
   page_load_metrics::mojom::PageLoadTiming subframe_timing;
   page_load_metrics::InitPageLoadTimingForTest(&subframe_timing);
@@ -1558,13 +1582,13 @@
       CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Load some bytes in each frame so they are considered ad iframes.
-  ResourceDataUpdate(ad_frame_none, ResourceCached::NOT_CACHED, 1);
-  ResourceDataUpdate(ad_frame_net, ResourceCached::NOT_CACHED, 1);
-  ResourceDataUpdate(ad_frame_cpu, ResourceCached::NOT_CACHED, 1);
-  ResourceDataUpdate(ad_frame_total_cpu, ResourceCached::NOT_CACHED, 1);
+  ResourceDataUpdate(ad_frame_none, ResourceCached::kNotCached, 1);
+  ResourceDataUpdate(ad_frame_net, ResourceCached::kNotCached, 1);
+  ResourceDataUpdate(ad_frame_cpu, ResourceCached::kNotCached, 1);
+  ResourceDataUpdate(ad_frame_total_cpu, ResourceCached::kNotCached, 1);
 
   // Make three of the ad frames hit thresholds for heavy ads.
-  ResourceDataUpdate(ad_frame_net, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame_net, ResourceCached::kNotCached,
                      (heavy_ad_thresholds::kMaxNetworkBytes / 1024));
   OnCpuTimingUpdate(
       ad_frame_cpu,
@@ -1622,13 +1646,13 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Load just under the threshold amount of bytes.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      (heavy_ad_thresholds::kMaxNetworkBytes / 1024) - 1);
   histogram_tester().ExpectTotalCount(
       SuffixedHistogram("HeavyAds.InterventionType2"), 0);
 
   // Load enough bytes to trigger the intervention.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 2);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 2);
 
   histogram_tester().ExpectUniqueSample(
       SuffixedHistogram("HeavyAds.InterventionType2"),
@@ -1647,13 +1671,13 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Load just under the threshold amount of bytes with noise included.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      (heavy_ad_thresholds::kMaxNetworkBytes / 1024) + 1);
   histogram_tester().ExpectTotalCount(
       SuffixedHistogram("HeavyAds.InterventionType2"), 0);
 
   // Load enough bytes to meet the noised threshold criteria.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 1);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 1);
 
   histogram_tester().ExpectUniqueSample(
       SuffixedHistogram("HeavyAds.InterventionType2"),
@@ -1674,7 +1698,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Load network bytes that trip the heavy ad threshold without noise.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      heavy_ad_thresholds::kMaxNetworkBytes / 1024 + 1);
   histogram_tester().ExpectTotalCount(
       SuffixedHistogram("HeavyAds.InterventionType2"), 0);
@@ -1703,7 +1727,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Load network bytes that trip the heavy ad threshold without noise.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      heavy_ad_thresholds::kMaxNetworkBytes / 1024 + 1);
   histogram_tester().ExpectTotalCount(
       SuffixedHistogram("HeavyAds.InterventionType2"), 0);
@@ -1735,7 +1759,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add some data to the ad frame so it get reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 1);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 1);
 
   // Use just under the threshold amount of CPU.Needs to spread across enough
   // windows to not trigger peak threshold.
@@ -1762,7 +1786,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add some data to the ad frame so it get reported.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED, 1);
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached, 1);
 
   // Use just under the peak threshold amount of CPU.
   OnCpuTimingUpdate(
@@ -1789,7 +1813,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add enough data to trigger the intervention.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      (kMaxHeavyAdNetworkBytes / 1024) + 1);
 
   histogram_tester().ExpectTotalCount(
@@ -1810,7 +1834,7 @@
   TriggerFirstUserActivation(ad_frame);
 
   // Add enough data to trigger the intervention.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      (heavy_ad_thresholds::kMaxNetworkBytes / 1024) + 1);
 
   histogram_tester().ExpectTotalCount(
@@ -1837,7 +1861,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add enough data to trigger the intervention.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      (heavy_ad_thresholds::kMaxNetworkBytes / 1024) + 1);
 
   histogram_tester().ExpectTotalCount(
@@ -1862,7 +1886,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add enough data to trigger the intervention.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      (heavy_ad_thresholds::kMaxNetworkBytes / 1024) + 1);
 
   histogram_tester().ExpectTotalCount(
@@ -1889,7 +1913,7 @@
   RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add enough data to trigger the intervention.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      (heavy_ad_thresholds::kMaxNetworkBytes / 1024) + 1);
 
   // Verify the intervention triggered.
@@ -1903,7 +1927,7 @@
   ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   // Add enough data to trigger the intervention.
-  ResourceDataUpdate(ad_frame, ResourceCached::NOT_CACHED,
+  ResourceDataUpdate(ad_frame, ResourceCached::kNotCached,
                      (heavy_ad_thresholds::kMaxNetworkBytes / 1024) + 1);
 
   // Verify the intervention did not occur again.
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
index fa14dba..8548027 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
@@ -101,10 +101,6 @@
     const page_load_metrics::mojom::ResourceDataUpdatePtr& resource,
     int process_id,
     const page_load_metrics::ResourceTracker& resource_tracker) {
-  // TODO(968141): Update these metrics to include resources loaded by the
-  // memory cache.
-  if (resource->cache_type == page_load_metrics::mojom::CacheType::kMemory)
-    return;
   bool is_same_origin = origin_.IsSameOriginWith(resource->origin);
   bytes_ += resource->delta_bytes;
   network_bytes_ += resource->delta_bytes;
@@ -256,7 +252,7 @@
   builder
       .SetLoading_NetworkBytes(
           ukm::GetExponentialBucketMinForBytes(network_bytes()))
-      .SetLoading_CacheBytes(
+      .SetLoading_CacheBytes2(
           ukm::GetExponentialBucketMinForBytes((bytes() - network_bytes())))
       .SetLoading_VideoBytes(ukm::GetExponentialBucketMinForBytes(
           GetAdNetworkBytesForMime(ResourceMimeType::kVideo)))
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
index e596cff..8fdda8d 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
@@ -329,8 +329,6 @@
       content::NavigationSimulator::CreateRendererInitiated(url, main_rfh());
   navigation->Fail(net::ERR_TIMED_OUT);
   navigation->AbortCommit();
-  content::RenderFrameHostTester::For(navigation->GetFinalRenderFrameHost())
-      ->SimulateNavigationStop();
 
   histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 0);
   histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0);
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
index 4137ad85..0e469ba4 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -183,7 +183,7 @@
   std::unique_ptr<content::NavigationSimulator> navigation =
       content::NavigationSimulator::CreateRendererInitiated(url, main_rfh());
   navigation->Fail(net::ERR_TIMED_OUT);
-  content::RenderFrameHostTester::For(main_rfh())->SimulateNavigationStop();
+  navigation->AbortCommit();
 
   // Simulate closing the tab.
   DeleteContents();
diff --git a/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.cc b/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.cc
index f73d0e0e..dcb9e00e 100644
--- a/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.cc
+++ b/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.cc
@@ -11,16 +11,16 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "components/performance_manager/graph/process_node_impl.h"
 #include "components/performance_manager/performance_manager_impl.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
 #include "components/performance_manager/render_process_user_data.h"
 #include "content/public/browser/render_process_host.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
 
 namespace {
 
 void BindProcessNode(
     int render_process_host_id,
-    mojo::PendingReceiver<resource_coordinator::mojom::ProcessCoordinationUnit>
+    mojo::PendingReceiver<performance_manager::mojom::ProcessCoordinationUnit>
         receiver) {
   content::RenderProcessHost* render_process_host =
       content::RenderProcessHost::FromID(render_process_host_id);
diff --git a/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.cc b/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.cc
index 32b94f5..afaa3650 100644
--- a/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.cc
+++ b/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.cc
@@ -12,7 +12,7 @@
 
 namespace performance_manager {
 
-using LifecycleState = resource_coordinator::mojom::LifecycleState;
+using LifecycleState = performance_manager::mojom::LifecycleState;
 
 // Provides FrozenFrameAggregator machinery access to some internals of a
 // PageNodeImpl and ProcessNodeImpl.
diff --git a/chrome/browser/performance_manager/decorators/page_aggregator.cc b/chrome/browser/performance_manager/decorators/page_aggregator.cc
index 1dc7131..92a41f8e 100644
--- a/chrome/browser/performance_manager/decorators/page_aggregator.cc
+++ b/chrome/browser/performance_manager/decorators/page_aggregator.cc
@@ -8,11 +8,11 @@
 
 #include "components/performance_manager/graph/node_attached_data_impl.h"
 #include "components/performance_manager/graph/page_node_impl.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
 
 namespace performance_manager {
 
-using resource_coordinator::mojom::InterventionPolicy;
+using performance_manager::mojom::InterventionPolicy;
 
 // Provides PageAggregator machinery access to some internals
 // of a PageNodeImpl.
diff --git a/chrome/browser/performance_manager/decorators/page_aggregator_unittest.cc b/chrome/browser/performance_manager/decorators/page_aggregator_unittest.cc
index 7164215..fc401a1f 100644
--- a/chrome/browser/performance_manager/decorators/page_aggregator_unittest.cc
+++ b/chrome/browser/performance_manager/decorators/page_aggregator_unittest.cc
@@ -8,13 +8,13 @@
 #include "components/performance_manager/graph/graph_impl_operations.h"
 #include "components/performance_manager/graph/process_node_impl.h"
 #include "components/performance_manager/public/graph/page_node.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
 #include "components/performance_manager/test_support/graph_test_harness.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace performance_manager {
 
-using resource_coordinator::mojom::InterventionPolicy;
+using performance_manager::mojom::InterventionPolicy;
 
 namespace {
 
diff --git a/chrome/browser/performance_manager/graph/page_node_impl_browsertest.cc b/chrome/browser/performance_manager/graph/page_node_impl_browsertest.cc
index 45e517c8..3a63105 100644
--- a/chrome/browser/performance_manager/graph/page_node_impl_browsertest.cc
+++ b/chrome/browser/performance_manager/graph/page_node_impl_browsertest.cc
@@ -156,15 +156,14 @@
 }
 
 void RunOriginTrialTestOnPMSequence(
-    const resource_coordinator::mojom::InterventionPolicy expected_policy) {
+    const mojom::InterventionPolicy expected_policy) {
   auto* perf_manager = PerformanceManagerImpl::GetInstance();
   ASSERT_TRUE(perf_manager);
   base::RunLoop run_loop;
   perf_manager->CallOnGraphImpl(
       FROM_HERE, base::BindOnce(
                      [](base::OnceClosure quit_closure,
-                        const resource_coordinator::mojom::InterventionPolicy
-                            expected_policy,
+                        const mojom::InterventionPolicy expected_policy,
                         performance_manager::GraphImpl* graph) {
                        auto page_nodes = graph->GetAllPageNodeImpls();
                        EXPECT_EQ(1U, page_nodes.size());
@@ -225,8 +224,7 @@
                      {kOriginTrialTestHostname,
                       kOriginTrialFreezePolicyTestPath, kOriginTrialOptInPage},
                      "/")));
-  RunOriginTrialTestOnPMSequence(
-      resource_coordinator::mojom::InterventionPolicy::kOptIn);
+  RunOriginTrialTestOnPMSequence(mojom::InterventionPolicy::kOptIn);
 }
 
 IN_PROC_BROWSER_TEST_F(PageNodeImplBrowserTest, PageFreezeOriginTrialOptOut) {
@@ -235,8 +233,7 @@
                      {kOriginTrialTestHostname,
                       kOriginTrialFreezePolicyTestPath, kOriginTrialOptOutPage},
                      "/")));
-  RunOriginTrialTestOnPMSequence(
-      resource_coordinator::mojom::InterventionPolicy::kOptOut);
+  RunOriginTrialTestOnPMSequence(mojom::InterventionPolicy::kOptOut);
 }
 
 IN_PROC_BROWSER_TEST_F(PageNodeImplBrowserTest, PageFreezeOriginTrialDefault) {
@@ -245,8 +242,7 @@
                                         kOriginTrialFreezePolicyTestPath,
                                         kOriginTrialDefaultPage},
                                        "/")));
-  RunOriginTrialTestOnPMSequence(
-      resource_coordinator::mojom::InterventionPolicy::kDefault);
+  RunOriginTrialTestOnPMSequence(mojom::InterventionPolicy::kDefault);
 }
 
 IN_PROC_BROWSER_TEST_F(PageNodeImplBrowserTest,
@@ -255,8 +251,7 @@
       browser(), GURL(base::JoinString({kOriginTrialTestHostname, k2iFramesPath,
                                         kOriginTrialOptInOptOut},
                                        "/")));
-  RunOriginTrialTestOnPMSequence(
-      resource_coordinator::mojom::InterventionPolicy::kOptOut);
+  RunOriginTrialTestOnPMSequence(mojom::InterventionPolicy::kOptOut);
 }
 
 IN_PROC_BROWSER_TEST_F(PageNodeImplBrowserTest,
@@ -265,8 +260,7 @@
       browser(), GURL(base::JoinString({kOriginTrialTestHostname, k2iFramesPath,
                                         kOriginTrialOptOutOptIn},
                                        "/")));
-  RunOriginTrialTestOnPMSequence(
-      resource_coordinator::mojom::InterventionPolicy::kOptOut);
+  RunOriginTrialTestOnPMSequence(mojom::InterventionPolicy::kOptOut);
 }
 
 IN_PROC_BROWSER_TEST_F(PageNodeImplBrowserTest,
@@ -275,8 +269,7 @@
       browser(), GURL(base::JoinString({kOriginTrialTestHostname, k2iFramesPath,
                                         kOriginTrialDefaultOptIn},
                                        "/")));
-  RunOriginTrialTestOnPMSequence(
-      resource_coordinator::mojom::InterventionPolicy::kOptIn);
+  RunOriginTrialTestOnPMSequence(mojom::InterventionPolicy::kOptIn);
 }
 
 IN_PROC_BROWSER_TEST_F(PageNodeImplBrowserTest,
@@ -285,8 +278,7 @@
       browser(), GURL(base::JoinString({kOriginTrialTestHostname, k2iFramesPath,
                                         kOriginTrialDefaultOptOut},
                                        "/")));
-  RunOriginTrialTestOnPMSequence(
-      resource_coordinator::mojom::InterventionPolicy::kOptOut);
+  RunOriginTrialTestOnPMSequence(mojom::InterventionPolicy::kOptOut);
 }
 
 IN_PROC_BROWSER_TEST_F(PageNodeImplBrowserTest,
@@ -295,8 +287,7 @@
       browser(), GURL(base::JoinString({kOriginTrialTestHostname, k2iFramesPath,
                                         kOriginTrialOptInOptIn},
                                        "/")));
-  RunOriginTrialTestOnPMSequence(
-      resource_coordinator::mojom::InterventionPolicy::kOptIn);
+  RunOriginTrialTestOnPMSequence(mojom::InterventionPolicy::kOptIn);
 }
 
 IN_PROC_BROWSER_TEST_F(PageNodeImplBrowserTest,
@@ -305,8 +296,7 @@
       browser(), GURL(base::JoinString({kOriginTrialTestHostname, k2iFramesPath,
                                         kOriginTrialOptOutOptOut},
                                        "/")));
-  RunOriginTrialTestOnPMSequence(
-      resource_coordinator::mojom::InterventionPolicy::kOptOut);
+  RunOriginTrialTestOnPMSequence(mojom::InterventionPolicy::kOptOut);
 }
 
 IN_PROC_BROWSER_TEST_F(PageNodeImplBrowserTest,
@@ -315,8 +305,7 @@
       browser(), GURL(base::JoinString({kOriginTrialTestHostname, k2iFramesPath,
                                         kOriginTrialDefaultDefault},
                                        "/")));
-  RunOriginTrialTestOnPMSequence(
-      resource_coordinator::mojom::InterventionPolicy::kDefault);
+  RunOriginTrialTestOnPMSequence(mojom::InterventionPolicy::kDefault);
 }
 
 // TODO(sebmarchand): Add more tests, e.g. a test where the main frame and a
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 69bf848..b74c87f 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1183,7 +1183,10 @@
     base::Value::Type::BOOLEAN },
   { key::kTotalMemoryLimitMb,
     prefs::kTotalMemoryLimitMb,
-    base::Value::Type::INTEGER }
+    base::Value::Type::INTEGER },
+  { key::kTLS13HardeningForLocalAnchorsEnabled,
+    prefs::kTLS13HardeningForLocalAnchorsEnabled,
+    base::Value::Type::BOOLEAN },
 };
 // clang-format on
 
diff --git a/chrome/browser/previews/hints_fetcher_browsertest.cc b/chrome/browser/previews/hints_fetcher_browsertest.cc
index 8c1c7da..93fc9c42 100644
--- a/chrome/browser/previews/hints_fetcher_browsertest.cc
+++ b/chrome/browser/previews/hints_fetcher_browsertest.cc
@@ -459,9 +459,8 @@
       return;
 
     base::flat_set<std::string> hosts_requested;
-    for (const auto& host : hints_request.hosts()) {
+    for (const auto& host : hints_request.hosts())
       hosts_requested.insert(host.host());
-    }
 
     EXPECT_EQ(expect_hints_request_for_hosts_.value().size(),
               hosts_requested.size());
@@ -1166,7 +1165,8 @@
           "OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch", false,
           4);
     }
-    EXPECT_EQ(IsOptimizationGuideKeyedServiceEnabled() ? 4u : 1u,
+    // Hints should not be fetched for the same host again.
+    EXPECT_EQ(IsOptimizationGuideKeyedServiceEnabled() ? 3u : 1u,
               count_hints_requests_received());
     RetryForHistogramUntilCountReached(
         histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
@@ -1388,11 +1388,13 @@
     return;
 
   // Populate expected hosts with hosts contained in the html response of
-  // search_results_page_url().
+  // search_results_page_url(). example2.com is contained in the HTML
+  // response, but hints for example2.com must not be fetched since they
+  // were pushed via kFetchHintsOverride switch above.
   base::flat_set<std::string> expected_hosts;
   expected_hosts.insert(GURL("https://foo.com").host());
   expected_hosts.insert(GURL("https://example.com").host());
-  expected_hosts.insert(GURL("https://example2.com").host());
+  expected_hosts.insert(GURL("https://example3.com").host());
   SetExpectedHintsRequestForHosts(expected_hosts);
 
   histogram_tester->ExpectTotalCount(
diff --git a/chrome/browser/previews/previews_lite_page_redirect_browsertest.cc b/chrome/browser/previews/previews_lite_page_redirect_browsertest.cc
index 327ee08..8c76ad3 100644
--- a/chrome/browser/previews/previews_lite_page_redirect_browsertest.cc
+++ b/chrome/browser/previews/previews_lite_page_redirect_browsertest.cc
@@ -1640,6 +1640,27 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_P(
+    PreviewsLitePageRedirectServerTimeoutBrowserTest,
+    DISABLE_ON_WIN_MAC_CHROMESOS(
+        LitePagePreviewsOriginProbe_ExternalFailureReported)) {
+  set_origin_probe_success(true);
+
+  base::HistogramTester histogram_tester;
+  ui_test_utils::NavigateToURL(browser(),
+                               HttpsLitePageURL(kSuccess, nullptr, -1));
+  VerifyPreviewNotLoaded();
+  ClearDeciderState();
+  histogram_tester.ExpectBucketCount(
+      "Previews.ServerLitePage.ServerResponse",
+      previews::LitePageRedirectServerResponse::kTimeout, 1);
+
+  WaitForServerProbe();
+
+  histogram_tester.ExpectUniqueSample(
+      "Availability.Prober.DidSucceed.AfterReportedFailure.Litepages", true, 1);
+}
+
 class PreviewsLitePageRedirectServerBadServerBrowserTest
     : public PreviewsLitePageRedirectServerBrowserTest {
  public:
diff --git a/chrome/browser/previews/previews_lite_page_redirect_decider.h b/chrome/browser/previews/previews_lite_page_redirect_decider.h
index f72ac5225..f4decb8 100644
--- a/chrome/browser/previews/previews_lite_page_redirect_decider.h
+++ b/chrome/browser/previews/previews_lite_page_redirect_decider.h
@@ -124,6 +124,10 @@
 
   bool has_drp_headers() const { return drp_headers_valid_; }
 
+  AvailabilityProber* litepages_service_prober() {
+    return litepages_service_prober_.get();
+  }
+
  private:
   // AvailabilityProber::Delegate:
   bool ShouldSendNextProbe() override;
diff --git a/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc b/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc
index 1b3d1b1..a82343b6 100644
--- a/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc
+++ b/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc
@@ -147,6 +147,26 @@
       base::BindOnce(&InvalidateDRPConfigOnUIThread, frame_tree_node_id));
 }
 
+void ReportConnectionFailureOnUIThread(int frame_tree_node_id) {
+  auto* web_contents =
+      content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
+  // If the WebContents has been closed this may be null.
+  if (!web_contents)
+    return;
+
+  PreviewsServiceFactory::GetForProfile(
+      Profile::FromBrowserContext(web_contents->GetBrowserContext()))
+      ->previews_lite_page_redirect_decider()
+      ->litepages_service_prober()
+      ->ReportExternalFailureAndRetry();
+}
+
+void ReportConnectionFailure(int frame_tree_node_id) {
+  base::PostTask(
+      FROM_HERE, {content::BrowserThread::UI, base::TaskPriority::USER_VISIBLE},
+      base::BindOnce(&ReportConnectionFailureOnUIThread, frame_tree_node_id));
+}
+
 const base::TimeDelta kBlacklistDuration = base::TimeDelta::FromDays(30);
 
 const net::NetworkTrafficAnnotationTag kPreviewsTrafficAnnotation =
@@ -225,6 +245,7 @@
   if (result_callback_.is_null())
     return;
 
+  ReportConnectionFailure(frame_tree_node_id_);
   UMA_HISTOGRAM_ENUMERATION("Previews.ServerLitePage.ServerResponse",
                             previews::LitePageRedirectServerResponse::kTimeout);
 
@@ -427,6 +448,9 @@
     return;
   }
 
+  if (status.error_code != net::OK)
+    ReportConnectionFailure(frame_tree_node_id_);
+
   base::UmaHistogramSparse(
       "Previews.ServerLitePage.ServerNetError.BeforeCommit",
       -status.error_code);
diff --git a/chrome/browser/profiles/avatar_menu.cc b/chrome/browser/profiles/avatar_menu.cc
index 58b72ef4..285366f 100644
--- a/chrome/browser/profiles/avatar_menu.cc
+++ b/chrome/browser/profiles/avatar_menu.cc
@@ -42,9 +42,6 @@
                        Browser* browser)
     : profile_list_(ProfileList::Create(profile_storage)),
       menu_actions_(AvatarMenuActions::Create()),
-#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-      supervised_user_observer_(this),
-#endif
       profile_storage_(profile_storage),
       observer_(observer),
       browser_(browser) {
diff --git a/chrome/browser/profiles/avatar_menu.h b/chrome/browser/profiles/avatar_menu.h
index ee6fd62b..39aca28 100644
--- a/chrome/browser/profiles/avatar_menu.h
+++ b/chrome/browser/profiles/avatar_menu.h
@@ -23,6 +23,7 @@
 #include "ui/gfx/image/image.h"
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+#include "chrome/browser/supervised_user/supervised_user_service.h"
 #include "chrome/browser/supervised_user/supervised_user_service_observer.h"
 #endif
 
@@ -31,7 +32,6 @@
 class Browser;
 class ProfileAttributesStorage;
 class ProfileList;
-class SupervisedUserService;
 
 // This class represents the menu-like interface used to select profiles,
 // such as the bubble that appears when the avatar icon is clicked in the
@@ -197,7 +197,7 @@
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
   // Observes changes to a supervised user's custodian info.
   ScopedObserver<SupervisedUserService, SupervisedUserServiceObserver>
-      supervised_user_observer_;
+      supervised_user_observer_{this};
 #endif
 
   // The storage that provides the profile attributes. Weak.
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index 652eac2..17b758c 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -671,53 +671,6 @@
   }
 }
 
-class ProfileWithoutMediaCacheBrowserTest : public ProfileBrowserTest {
- public:
-  ProfileWithoutMediaCacheBrowserTest() {
-    feature_list_.InitAndEnableFeature(features::kUseSameCacheForMedia);
-  }
-
-  ~ProfileWithoutMediaCacheBrowserTest() override {}
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-// Verifies that when kUseSameCacheForMedia is enabled, the media
-// URLRequestContext uses the same disk cache as the main one.
-IN_PROC_BROWSER_TEST_F(ProfileWithoutMediaCacheBrowserTest,
-                       NoSeparateMediaCache) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  // Do a normal load using the media URLRequestContext, populating the cache.
-  SimpleURLLoaderHelper simple_loader_helper(
-      // TODO(svillar): this should be media request
-      content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
-          ->GetURLLoaderFactoryForBrowserProcess()
-          .get(),
-      embedded_test_server()->GetURL("/cachetime"), net::OK);
-  simple_loader_helper.WaitForCompletion();
-
-  // Cache-only load from the main request context should succeed, since the
-  // media request context uses the same cache.
-  SimpleURLLoaderHelper simple_loader_helper2(
-      content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
-          ->GetURLLoaderFactoryForBrowserProcess()
-          .get(),
-      embedded_test_server()->GetURL("/cachetime"), net::OK,
-      net::LOAD_ONLY_FROM_CACHE);
-  simple_loader_helper2.WaitForCompletion();
-
-  // Cache-only load from the media request context should also succeed.
-  SimpleURLLoaderHelper simple_loader_helper3(
-      content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
-          ->GetURLLoaderFactoryForBrowserProcess()
-          .get(),
-      embedded_test_server()->GetURL("/cachetime"), net::OK,
-      net::LOAD_ONLY_FROM_CACHE);
-  simple_loader_helper3.WaitForCompletion();
-}
-
 namespace {
 
 // Watches for the destruction of the specified path (Which, in the tests that
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
index 76632ca..4339c51 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
@@ -380,9 +380,9 @@
 }
 
 void TabLifecycleUnitSource::TabLifecycleUnit::UpdateLifecycleState(
-    mojom::LifecycleState state) {
+    performance_manager::mojom::LifecycleState state) {
   switch (state) {
-    case mojom::LifecycleState::kFrozen: {
+    case performance_manager::mojom::LifecycleState::kFrozen: {
       switch (GetState()) {
         case LifecycleUnitState::PENDING_DISCARD: {
           freeze_timeout_timer_->Stop();
@@ -405,7 +405,7 @@
       break;
     }
 
-    case mojom::LifecycleState::kRunning: {
+    case performance_manager::mojom::LifecycleState::kRunning: {
       SetState(LifecycleUnitState::ACTIVE,
                StateChangeReason::RENDERER_INITIATED);
       break;
@@ -419,7 +419,7 @@
 }
 
 void TabLifecycleUnitSource::TabLifecycleUnit::UpdateOriginTrialFreezePolicy(
-    mojom::InterventionPolicy policy) {
+    performance_manager::mojom::InterventionPolicy policy) {
   origin_trial_freeze_policy_ = policy;
 }
 
@@ -1024,16 +1024,16 @@
 
   // Apply origin trial opt-in/opt-out (policy is per page).
   switch (origin_trial_freeze_policy_) {
-    case mojom::InterventionPolicy::kUnknown:
+    case performance_manager::mojom::InterventionPolicy::kUnknown:
       decision_details->AddReason(DecisionFailureReason::ORIGIN_TRIAL_UNKNOWN);
       break;
-    case mojom::InterventionPolicy::kOptOut:
+    case performance_manager::mojom::InterventionPolicy::kOptOut:
       decision_details->AddReason(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT);
       break;
-    case mojom::InterventionPolicy::kOptIn:
+    case performance_manager::mojom::InterventionPolicy::kOptIn:
       decision_details->AddReason(DecisionSuccessReason::ORIGIN_TRIAL_OPT_IN);
       break;
-    case mojom::InterventionPolicy::kDefault:
+    case performance_manager::mojom::InterventionPolicy::kDefault:
       // Let other heuristics determine whether the tab can be frozen.
       break;
   }
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit.h b/chrome/browser/resource_coordinator/tab_lifecycle_unit.h
index 9fcdc00..fca045fc 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit.h
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit.h
@@ -13,10 +13,10 @@
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h"
 #include "chrome/browser/resource_coordinator/time.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
 #include "content/public/browser/visibility.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/page_importance_signals.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
 
 class TabStripModel;
 
@@ -88,10 +88,11 @@
 
   // Updates the tab's lifecycle state when changed outside the tab lifecycle
   // unit.
-  void UpdateLifecycleState(mojom::LifecycleState state);
+  void UpdateLifecycleState(performance_manager::mojom::LifecycleState state);
 
   // Updates the tab's origin trial freeze policy.
-  void UpdateOriginTrialFreezePolicy(mojom::InterventionPolicy policy);
+  void UpdateOriginTrialFreezePolicy(
+      performance_manager::mojom::InterventionPolicy policy);
 
   // Setters for the WebLock and IndexedDB lock usage properties.
   void SetIsHoldingWebLock(bool is_holding_weblock);
@@ -212,8 +213,8 @@
 
   // The freeze policy set via origin trial. Initial value is kDefault to avoid
   // affecting CanFreeze() before the policy is set for the first time.
-  mojom::InterventionPolicy origin_trial_freeze_policy_ =
-      mojom::InterventionPolicy::kDefault;
+  performance_manager::mojom::InterventionPolicy origin_trial_freeze_policy_ =
+      performance_manager::mojom::InterventionPolicy::kDefault;
 
   // Maintains the most recent LifecycleUnitDiscardReason that was passed into
   // Discard().
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
index ba3232c6..6b62c42 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
@@ -77,7 +77,7 @@
  private:
   static void OnLifecycleStateChangedImpl(
       const WebContentsProxy& contents_proxy,
-      mojom::LifecycleState state) {
+      performance_manager::mojom::LifecycleState state) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     // If the web contents is still alive then dispatch to the actual
     // implementation in TabLifecycleUnitSource.
@@ -87,7 +87,7 @@
 
   static void OnOriginTrialFreezePolicyChangedImpl(
       const WebContentsProxy& contents_proxy,
-      mojom::InterventionPolicy policy) {
+      performance_manager::mojom::InterventionPolicy policy) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     // If the web contents is still alive then dispatch to the actual
     // implementation in TabLifecycleUnitSource.
@@ -404,7 +404,7 @@
 // static
 void TabLifecycleUnitSource::OnLifecycleStateChanged(
     content::WebContents* web_contents,
-    mojom::LifecycleState state) {
+    performance_manager::mojom::LifecycleState state) {
   TabLifecycleUnit* lifecycle_unit = GetTabLifecycleUnit(web_contents);
 
   // Some WebContents aren't attached to a tab, so there is no corresponding
@@ -417,7 +417,7 @@
 // static
 void TabLifecycleUnitSource::OnOriginTrialFreezePolicyChanged(
     content::WebContents* web_contents,
-    mojom::InterventionPolicy policy) {
+    performance_manager::mojom::InterventionPolicy policy) {
   TabLifecycleUnit* lifecycle_unit = GetTabLifecycleUnit(web_contents);
 
   // Some WebContents aren't attached to a tab, so there is no corresponding
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
index 2387e05f..8de7043 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
@@ -14,8 +14,8 @@
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/browser_tab_strip_tracker.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
-#include "services/resource_coordinator/public/mojom/lifecycle.mojom.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
+#include "components/performance_manager/public/mojom/lifecycle.mojom.h"
 
 class PrefChangeRegistrar;
 class PrefService;
@@ -149,11 +149,12 @@
 
   // This is called indirectly from the corresponding event on a PageNode in the
   // performance_manager Graph.
-  static void OnLifecycleStateChanged(content::WebContents* web_contents,
-                                      mojom::LifecycleState state);
+  static void OnLifecycleStateChanged(
+      content::WebContents* web_contents,
+      performance_manager::mojom::LifecycleState state);
   static void OnOriginTrialFreezePolicyChanged(
       content::WebContents* web_contents,
-      mojom::InterventionPolicy policy);
+      performance_manager::mojom::InterventionPolicy policy);
   static void OnIsHoldingWebLockChanged(content::WebContents* web_contents,
                                         bool is_holding_weblock);
   static void OnIsHoldingIndexedDBLockChanged(
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
index 190bb2b..5aede05 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
@@ -630,7 +630,8 @@
 
   // Tab cannot be frozen if it opted-out via origin trial.
   TabLifecycleUnitSource::OnOriginTrialFreezePolicyChanged(
-      background_contents, mojom::InterventionPolicy::kOptOut);
+      background_contents,
+      performance_manager::mojom::InterventionPolicy::kOptOut);
   EXPECT_FALSE(background_lifecycle_unit->CanFreeze(&decision_details));
   EXPECT_FALSE(decision_details.IsPositive());
   EXPECT_EQ(DecisionFailureReason::ORIGIN_TRIAL_OPT_OUT,
@@ -656,7 +657,8 @@
 
   // Tab cannot be frozen if its origin trial policy is still unknown.
   TabLifecycleUnitSource::OnOriginTrialFreezePolicyChanged(
-      background_contents, mojom::InterventionPolicy::kUnknown);
+      background_contents,
+      performance_manager::mojom::InterventionPolicy::kUnknown);
   EXPECT_FALSE(background_lifecycle_unit->CanFreeze(&decision_details));
   EXPECT_FALSE(decision_details.IsPositive());
   EXPECT_EQ(DecisionFailureReason::ORIGIN_TRIAL_UNKNOWN,
@@ -700,7 +702,8 @@
   // The background tab can be frozen if it opted-in via origin trial, even if
   // it uses notifications in background.
   TabLifecycleUnitSource::OnOriginTrialFreezePolicyChanged(
-      background_contents, mojom::InterventionPolicy::kOptIn);
+      background_contents,
+      performance_manager::mojom::InterventionPolicy::kOptIn);
   EXPECT_TRUE(background_lifecycle_unit->CanFreeze(&decision_details));
   EXPECT_TRUE(decision_details.IsPositive());
   EXPECT_EQ(DecisionSuccessReason::ORIGIN_TRIAL_OPT_IN,
@@ -709,7 +712,8 @@
 
   // The foreground tab cannot be frozen, even if it opted-in via origin trial.
   TabLifecycleUnitSource::OnOriginTrialFreezePolicyChanged(
-      foreground_contents, mojom::InterventionPolicy::kOptIn);
+      foreground_contents,
+      performance_manager::mojom::InterventionPolicy::kOptIn);
   EXPECT_FALSE(foreground_lifecycle_unit->CanFreeze(&decision_details));
   EXPECT_FALSE(decision_details.IsPositive());
   EXPECT_EQ(DecisionFailureReason::LIVE_STATE_VISIBLE,
@@ -781,7 +785,8 @@
 
   reinterpret_cast<TabLifecycleUnitSource::TabLifecycleUnit*>(
       background_lifecycle_unit)
-      ->UpdateLifecycleState(mojom::LifecycleState::kFrozen);
+      ->UpdateLifecycleState(
+          performance_manager::mojom::LifecycleState::kFrozen);
   EXPECT_EQ(LifecycleUnitState::DISCARDED,
             background_lifecycle_unit->GetState());
   EXPECT_CALL(tab_observer_,
diff --git a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
index 162b40f..23cdfaf8 100644
--- a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
@@ -300,7 +300,8 @@
   void SimulateFreezeSignal(content::WebContents* contents) {
     GetTabLifecycleUnitSource()
         ->GetTabLifecycleUnit(contents)
-        ->UpdateLifecycleState(mojom::LifecycleState::kFrozen);
+        ->UpdateLifecycleState(
+            performance_manager::mojom::LifecycleState::kFrozen);
   }
 
   TabManager* tab_manager() { return g_browser_process->GetTabManager(); }
@@ -1270,7 +1271,8 @@
   // Pretend that the background tab reported its origin trial freeze policy, to
   // prevent CanFreeze() from returning false.
   TabLifecycleUnitSource::OnOriginTrialFreezePolicyChanged(
-      GetWebContentsAt(1), mojom::InterventionPolicy::kDefault);
+      GetWebContentsAt(1),
+      performance_manager::mojom::InterventionPolicy::kDefault);
 
   // Proactively discard the background tab.
   EXPECT_EQ(LifecycleUnitState::ACTIVE, GetLifecycleUnitAt(1)->GetState());
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 438f48e7..2546a28 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -259,12 +259,12 @@
 
   void SimulateFreezeCompletion(content::WebContents* content) {
     GetTabLifecycleUnit(content)->UpdateLifecycleState(
-        mojom::LifecycleState::kFrozen);
+        performance_manager::mojom::LifecycleState::kFrozen);
   }
 
   void SimulateUnfreezeCompletion(content::WebContents* content) {
     GetTabLifecycleUnit(content)->UpdateLifecycleState(
-        mojom::LifecycleState::kRunning);
+        performance_manager::mojom::LifecycleState::kRunning);
   }
 
   virtual void CheckThrottleResults(
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/i_search.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/i_search.js
index e449cd5..91d22b1d 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/i_search.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/i_search.js
@@ -40,8 +40,11 @@
   /**
    * Called when search result node changes.
    * @param {!AutomationNode} node The new search result.
+   * @param {number} start The index into the name where the search match
+   *     starts.
+   * @param {number} end The index into the name where the search match ends.
    */
-  onSearchResultChanged: function(node) {}
+  onSearchResultChanged: function(node, start, end) {}
 };
 
 /**
@@ -60,6 +63,9 @@
   /** @type {!cursors.Cursor} */
   this.cursor = cursors.Cursor.fromNode(leaf);
 
+  /** @private {number} */
+  this.callbackId_ = 0;
+
   // Global exports.
   /** Exported for this background script. */
   cvox.ChromeVox = chrome.extension.getBackgroundPage()['cvox']['ChromeVox'];
@@ -77,40 +83,41 @@
    * Performs a search.
    * @param {string} searchStr
    * @param {Dir} dir
+   * @param {boolean=} opt_nextObject
    */
-  search: function(searchStr, dir) {
-    searchStr = searchStr.toLocaleLowerCase();
-    var node = this.cursor.node;
-    var result = node;
-    var prev = node;
-    do {
-      // Because Closure cannot infer much about prev.
-      if (!prev)
-        break;
+  search: function(searchStr, dir, opt_nextObject) {
+    clearTimeout(this.callbackId_);
+    var step = function() {
+      searchStr = searchStr.toLocaleLowerCase();
+      var node = this.cursor.node;
+      var result = node;
 
-      // We want to start/continue the search at the next object.
-      result =
-          AutomationUtil.findNextNode(prev, dir, AutomationPredicate.object);
-
-      if (!result)
-        break;
-
-      // Ask native to search the underlying data for a performance boost.
-      prev = result;
-      result = result.getNextTextMatch(searchStr, dir == Dir.BACKWARD);
-      prev = result || prev;
-
-      // Check to ensure we have an object-like node; otherwise, continue.
-      if (result && !AutomationPredicate.object(result))
-        continue;
-    } while (!result);
-
-    if (result) {
-      this.cursor = cursors.Cursor.fromNode(result);
-      this.handler_.onSearchResultChanged(result);
-    } else {
-      this.handler_.onSearchReachedBoundary(this.cursor.node);
+      if (opt_nextObject) {
+        // We want to start/continue the search at the next object.
+        result =
+            AutomationUtil.findNextNode(node, dir, AutomationPredicate.object);
       }
+
+      do {
+        // Ask native to search the underlying data for a performance boost.
+        result = result.getNextTextMatch(searchStr, dir == Dir.BACKWARD);
+      } while (result && !AutomationPredicate.object(result));
+
+      if (result) {
+        this.cursor = cursors.Cursor.fromNode(result);
+        var start = result.name.toLocaleLowerCase().indexOf(searchStr);
+        var end = start + searchStr.length;
+        this.handler_.onSearchResultChanged(result, start, end);
+      } else {
+        this.handler_.onSearchReachedBoundary(this.cursor.node);
+      }
+    };
+
+    this.callbackId_ = setTimeout(step.bind(this), 0);
+  },
+
+  clear: function() {
+    clearTimeout(this.callbackId_);
   }
 };
 
@@ -183,7 +190,7 @@
       default:
         return false;
     }
-    this.iSearch_.search(this.input_.value, this.dir_);
+    this.iSearch_.search(this.input_.value, this.dir_, true);
     evt.preventDefault();
     evt.stopPropagation();
     return false;
@@ -196,6 +203,7 @@
    */
   onTextInput: function(evt) {
     var searchStr = evt.target.value + evt.data;
+    this.iSearch_.clear();
     this.iSearch_.search(searchStr, this.dir_);
     return true;
   },
@@ -211,21 +219,31 @@
   /**
    * @override
    */
-  onSearchResultChanged: function(node) {
-    this.output_(node);
+  onSearchResultChanged: function(node, start, end) {
+    this.output_(node, start, end);
   },
 
   /**
    * @param {!AutomationNode} node
+   * @param {number=} opt_start
+   * @param {number=} opt_end
    * @private
    */
-  output_: function(node) {
+  output_: function(node, opt_start, opt_end) {
     Output.forceModeForNextSpeechUtterance(cvox.QueueMode.FLUSH);
-    var o =
-        new Output()
-            .withRichSpeechAndBraille(
-                cursors.Range.fromNode(node), null, Output.EventType.NAVIGATE)
-            .go();
+    var o = new Output();
+    if (opt_start && opt_end) {
+      o.withString([
+        node.name.substr(0, opt_start),
+        node.name.substr(opt_start, opt_end - opt_start),
+        node.name.substr(opt_end)
+      ].join(', '));
+      o.format('$role', node);
+    } else {
+      o.withRichSpeechAndBraille(
+          cursors.Range.fromNode(node), null, Output.EventType.NAVIGATE);
+    }
+    o.go();
 
     this.background_.setCurrentRange(cursors.Range.fromNode(node));
   },
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/i_search_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/i_search_test.extjs
index 9f004358..bf41ef9 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/i_search_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/i_search_test.extjs
@@ -46,17 +46,23 @@
 FakeISearchHandler.prototype = {
   /** @override */
   onSearchReachedBoundary: function(boundaryNode) {
-    this.expect_.shift()(boundaryNode, true);
+    this.expect_.shift()({node: boundaryNode, isBoundary: true});
   },
 
-  onSearchResultChanged: function(node) {
-    this.expect_.shift()(node);
+  /** @override */
+  onSearchResultChanged: function(node, start, end) {
+    this.expect_.shift()({node: node,
+                          start: start,
+                          end: end});
   },
 
   expect: function(str, opt_callback) {
-    this.expect_.push(this.test.newCallback(function(node, isBound) {
+    this.expect_.push(this.test.newCallback(function(args) {
+      var node = args.node;
       var actual = node.name || node.role;
-      if (isBound)
+      if (args.start && args.end)
+        actual = 'start=' + args.start + ' end=' + args.end + ' text=' + actual;
+      if (args.isBoundary)
         actual = 'boundary=' + actual;
       assertEquals(str, actual);
       opt_callback && opt_callback();
@@ -64,15 +70,15 @@
   }
 };
 
-TEST_F('ChromeVoxISearchTest', 'DISABLED_Simple', function() {
+TEST_F('ChromeVoxISearchTest', 'Simple', function() {
   this.runWithLoadedTree(this.linksAndHeadingsDoc, function(rootNode) {
     var handler = new FakeISearchHandler(this);
-    var search = new ISearch(rootNode);
+    var search = new ISearch(new cursors.Cursor(rootNode, 0));
     search.handler = handler;
 
     // Simple forward search.
     search.search('US', 'forward');
-    handler.expect('About US',
+    handler.expect('start=6 end=8 text=About US',
                    search.search.bind(search, 'start', 'backward'));
 
     handler.expect('start',
@@ -88,9 +94,14 @@
                    // Mixed case substring.
                    search.search.bind(search, 'bReak', 'forward'));
 
-    handler.expect('Latest Breaking News',
-                   search.search.bind(search, 'bReak', 'forward'));
+    handler.expect('start=7 end=12 text=Latest Breaking News',
+                   search.search.bind(search, 'bReaki', 'forward'));
 
+    // Incremental search stays on the current node.
+    handler.expect('start=7 end=13 text=Latest Breaking News',
+                                     search.search.bind(search, 'bReakio', 'forward'));
+
+    // No results for the search.
     handler.expect('boundary=Latest Breaking News');
   });
 });
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.js
index 288e914..7f70b33 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.js
@@ -380,25 +380,37 @@
     }
   }, this));
 
-  // Add all open tabs to the Tabs menu.
-  bkgnd.chrome.windows.getLastFocused(function(lastFocusedWindow) {
-    bkgnd.chrome.windows.getAll({'populate': true}, function(windows) {
-      for (var i = 0; i < windows.length; i++) {
-        var tabs = windows[i].tabs;
-        for (var j = 0; j < tabs.length; j++) {
-          var title = tabs[j].title;
-          if (tabs[j].active && windows[i].id == lastFocusedWindow.id)
-            title += ' ' + Msgs.getMsg('active_tab');
-          tabsMenu.addMenuItem(
-              title, '', '', '', (function(win, tab) {
-                                   bkgnd.chrome.windows.update(
-                                       win.id, {focused: true}, function() {
-                                         bkgnd.chrome.tabs.update(
-                                             tab.id, {active: true});
-                                       });
-                                 }).bind(this, windows[i], tabs[j]));
+  // Only add all open tabs to the Tabs menu if we are logged in.
+  chrome.loginState.getSessionState(function(
+      /** @type {string} */ sessionState) {
+    if (sessionState === 'IN_OOBE_SCREEN' ||
+        sessionState === 'IN_LOGIN_SCREEN' ||
+        sessionState === 'IN_LOCK_SCREEN') {
+      tabsMenu.addMenuItem(
+          Msgs.getMsg('panel_menu_item_none'), '', '', '', function() {});
+      return;
+    }
+
+    // Add all open tabs to the Tabs menu.
+    bkgnd.chrome.windows.getLastFocused(function(lastFocusedWindow) {
+      bkgnd.chrome.windows.getAll({'populate': true}, function(windows) {
+        for (var i = 0; i < windows.length; i++) {
+          var tabs = windows[i].tabs;
+          for (var j = 0; j < tabs.length; j++) {
+            var title = tabs[j].title;
+            if (tabs[j].active && windows[i].id == lastFocusedWindow.id)
+              title += ' ' + Msgs.getMsg('active_tab');
+            tabsMenu.addMenuItem(
+                title, '', '', '', (function(win, tab) {
+                                     bkgnd.chrome.windows.update(
+                                         win.id, {focused: true}, function() {
+                                           bkgnd.chrome.tabs.update(
+                                               tab.id, {active: true});
+                                         });
+                                   }).bind(this, windows[i], tabs[j]));
+          }
         }
-      }
+      });
     });
   });
 
diff --git a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
index e43f124..6bf8fe7 100644
--- a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
@@ -25,6 +25,7 @@
     "downloads",
     "experimental",
     "history",
+    "loginState",
     "metricsPrivate",
     "notifications",
     "settingsPrivate",
diff --git a/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py b/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py
index 0dab9310..a77193d7 100755
--- a/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py
+++ b/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py
@@ -58,6 +58,10 @@
 _METRICS_PRIVATE_EXTERNS = (
     ChromeRootPath('third_party/closure_compiler/externs/metrics_private.js'))
 
+# LoginState externs file.
+_LOGIN_STATE_EXTERNS = (
+    ChromeRootPath('third_party/closure_compiler/externs/login_state.js'))
+
 # Settings private API externs file.
 _SETTINGS_PRIVATE_EXTERNS = (
     ChromeRootPath('third_party/closure_compiler/externs/settings_private.js'))
@@ -89,6 +93,7 @@
     _CHROME_EXTENSIONS_EXTERNS,
     _COMMANDLINE_PRIVATE_EXTERNS,
     _METRICS_PRIVATE_EXTERNS,
+    _LOGIN_STATE_EXTERNS,
     _SETTINGS_PRIVATE_EXTERNS,]
 
 # List of top-level scripts and externs that we can check.
diff --git a/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json b/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
index e59dd858..adb486f 100644
--- a/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
+++ b/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
@@ -629,7 +629,7 @@
       "name": "__MSG_keyboard_catalan__",
       "type": "ime",
       "id": "xkb:es:cat:cat",
-      "indicator": "CAS",
+      "indicator": "CAT",
       "description": "",
       "language": [
         "ca"
diff --git a/chrome/browser/resources/chromeos/input_method/xkb_manifest.json b/chrome/browser/resources/chromeos/input_method/xkb_manifest.json
index 0bc467a..d32c97c 100644
--- a/chrome/browser/resources/chromeos/input_method/xkb_manifest.json
+++ b/chrome/browser/resources/chromeos/input_method/xkb_manifest.json
@@ -494,7 +494,7 @@
       "name": "__MSG_keyboard_catalan__",
       "type": "ime",
       "id": "xkb:es:cat:cat",
-      "indicator": "CAS",
+      "indicator": "CAT",
       "description": "",
       "language": [
         "ca"
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js
index dfb95423..ebc819a 100644
--- a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js
+++ b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js
@@ -94,10 +94,10 @@
 
     // Set default managedProperties_ until they are loaded.
     this.propertiesReceived_ = false;
+    this.deviceState_ = null;
     this.managedProperties_ = OncMojo.getDefaultManagedProperties(
         OncMojo.getNetworkTypeFromString(type), this.guid, name);
     this.getNetworkDetails_();
-    this.getDeviceState_();
   },
 
   /** @override */
@@ -182,10 +182,11 @@
 
   /** CrosNetworkConfigObserver impl */
   onDeviceStateListChanged: function() {
-    this.getDeviceState_();
-    if (this.guid) {
-      this.getNetworkDetails_();
+    if (!this.guid || !this.managedProperties_) {
+      return;
     }
+    this.getDeviceState_();
+    this.getNetworkDetails_();
   },
 
   /** @private */
@@ -199,16 +200,21 @@
       }
       this.managedProperties_ = response.result;
       this.propertiesReceived_ = true;
+      if (!this.deviceState_) {
+        this.getDeviceState_();
+      }
     });
   },
 
   /** @private */
   getDeviceState_: function() {
+    if (!this.managedProperties_) {
+      return;
+    }
+    const type = this.managedProperties_.type;
     this.networkConfig_.getDeviceStateList().then(response => {
       const devices = response.result;
-      this.deviceState_ =
-          devices.find(device => device.type == this.managedProperties_.type) ||
-          null;
+      this.deviceState_ = devices.find(device => device.type == type) || null;
     });
   },
 
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css b/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
index 891deb9f..d83e857b 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
@@ -750,6 +750,10 @@
   visibility: hidden;  /* Need this for correct positioning. */
 }
 
+#current-wallpaper-info-bar .spacer {
+  flex: 1;
+}
+
 :not(.preview-mode) #current-wallpaper-info-bar.show-info-bar {
   visibility: visible;
 }
@@ -800,12 +804,6 @@
   display: flex;
   flex-direction: column;
   font-size: 12px;
-  position: absolute;
-  right: 0;
-}
-
-html[dir='rtl'] #current-wallpaper-more-options {
-  right: 420px;
 }
 
 #current-wallpaper-more-options > div {
@@ -825,7 +823,12 @@
 }
 
 #current-wallpaper-more-options .text {
-  padding-top: 1px;
+  height: 16px;
+  line-height: 16px;
+  max-width: 160px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
 }
 
 #current-wallpaper-more-options .icon {
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/main.html b/chrome/browser/resources/chromeos/wallpaper_manager/main.html
index 2b78418..bcf951f 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/main.html
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/main.html
@@ -104,6 +104,7 @@
               <div id="current-wallpaper-title"></div>
               <div id="current-wallpaper-description"></div>
             </div>
+            <div class="spacer"></div>
             <div id="current-wallpaper-more-options">
               <div id="refresh">
                 <div class="icon"></div>
diff --git a/chrome/browser/resources/extensions/toolbar.html b/chrome/browser/resources/extensions/toolbar.html
index 9b8706b..38cf1124 100644
--- a/chrome/browser/resources/extensions/toolbar.html
+++ b/chrome/browser/resources/extensions/toolbar.html
@@ -97,10 +97,11 @@
         narrow-threshold="1000">
       <div class="more-actions">
         <span id="devModeLabel">$i18n{toolbarDevMode}</span>
-        <cr-tooltip-icon hidden$="[[!devModeControlledByPolicy]]"
-            tooltip-text="$i18n{controlledSettingPolicy}"
-            icon-class="cr20:domain"
-            icon-aria-label="$i18n{controlledSettingPolicy}">
+        <cr-tooltip-icon hidden="[[!shouldDisableDevMode_(
+            devModeControlledByPolicy, isSupervised)]]"
+            tooltip-text="[[getTooltipText_(isSupervised)]]"
+            icon-class="[[getIcon_(isSupervised)]]"
+            icon-aria-label="[[getTooltipText_(isSupervised)]]">
         </cr-tooltip-icon>
         <cr-toggle id="devMode" on-change="onDevModeToggleChange_"
             disabled="[[shouldDisableDevMode_(
diff --git a/chrome/browser/resources/extensions/toolbar.js b/chrome/browser/resources/extensions/toolbar.js
index bd3590e..228cc45 100644
--- a/chrome/browser/resources/extensions/toolbar.js
+++ b/chrome/browser/resources/extensions/toolbar.js
@@ -76,6 +76,24 @@
     },
 
     /**
+     * @return {string}
+     * @private
+     */
+    getTooltipText_: function() {
+      return this.i18n(
+          this.isSupervised ? 'controlledSettingChildRestriction' :
+                              'controlledSettingPolicy');
+    },
+
+    /**
+     * @return {string}
+     * @private
+     */
+    getIcon_: function() {
+      return this.isSupervised ? 'cr20:kite' : 'cr20:domain';
+    },
+
+    /**
      * @param {!CustomEvent<boolean>} e
      * @private
      */
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 7d9a40f..119a2d2 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -236,7 +236,7 @@
   background-position-x: calc(100% - 16px);
 }
 
-#realbox-matches a.removable {
+#realbox-matches.removable a {
   padding-inline-end: 48px;
 }
 
@@ -304,15 +304,16 @@
 }
 
 #realbox-matches .remove-icon {
-  -webkit-appearance: none;
+  height: 100%;
+  width: 100%;
+}
+
+#realbox-matches a:-webkit-any(:hover, :focus-within) .remove-icon {
   -webkit-mask-image: url(../../../../ui/webui/resources/images/icon_clear.svg);
   -webkit-mask-position: center;
   -webkit-mask-repeat: no-repeat;
   -webkit-mask-size: 16px;
   background-color: rgb(var(--GG900-rgb));
-  border: none;
-  height: 100%;
-  width: 100%;
 }
 
 #fakebox > input {
@@ -837,13 +838,11 @@
 }
 
 #promo > div .dismiss-icon {
-  -webkit-appearance: none;
   -webkit-mask-image: url(../../../../ui/webui/resources/images/icon_clear.svg);
   -webkit-mask-position: center center;
   -webkit-mask-repeat: no-repeat;
   -webkit-mask-size: 16px;
   background-color: rgb(var(--dismiss-background-rgb));
-  border: none;
   display: block;
   height: 100%;
   outline: none;
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index 92685fc..5e3941a1 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -1241,7 +1241,7 @@
   }
 
   if (key === 'Enter') {
-    if (matchEls[selected]) {
+    if (matchEls[selected] && matchEls.concat(realboxEl).includes(e.target)) {
       // Note: dispatching a MouseEvent here instead of using e.g. .click() as
       // this forwards key modifiers. This enables Shift+Enter to open a match
       // in a new window, for example.
@@ -1448,7 +1448,7 @@
 
       remove.appendChild(icon);
       matchEl.appendChild(remove);
-      matchEl.classList.add(CLASSES.REMOVABLE);
+      realboxMatchesEl.classList.add(CLASSES.REMOVABLE);
     }
 
     // TODO(crbug.com/1002689): set a more useful aria-label on |matchEl|, as
diff --git a/chrome/browser/resources/omnibox/omnibox.html b/chrome/browser/resources/omnibox/omnibox.html
index 402bef0..d5284f5 100644
--- a/chrome/browser/resources/omnibox/omnibox.html
+++ b/chrome/browser/resources/omnibox/omnibox.html
@@ -268,10 +268,9 @@
     <span class="label">
       all providers done = <span id="done"></span>
     </span>
+    <span class="label">type = <span id="type"></span></span>
     <span class="label">host = <span id="host"></span></span>
-    <span class="label">
-      has isTypedHost = <span id="is-typed-host"></span>
-    </span>
+    <span class="label">is typed host = <span id="is-typed-host"></span></span>
   </template>
 
   <omnibox-input id="omnibox-input"></omnibox-input>
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js
index c5d0e722..b27b8b8e 100644
--- a/chrome/browser/resources/omnibox/omnibox.js
+++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -158,7 +158,6 @@
   exportDelegate = new ExportDelegate(omniboxOutput, omniboxInput);
 
   omniboxInput.addEventListener('query-inputs-changed', e => {
-    omniboxOutput.updateQueryInputs(e.detail);
     browserProxy.makeRequest(
         e.detail.inputText, e.detail.resetAutocompleteController,
         e.detail.cursorPosition, e.detail.zeroSuggest,
@@ -211,7 +210,6 @@
     }
     this.omniboxInput_.queryInputs = importData.queryInputs;
     this.omniboxInput_.displayInputs = importData.displayInputs;
-    this.omniboxOutput_.updateQueryInputs(importData.queryInputs);
     this.omniboxOutput_.updateDisplayInputs(importData.displayInputs);
     this.omniboxOutput_.setResponsesHistory(importData.responsesHistory);
     return true;
diff --git a/chrome/browser/resources/omnibox/omnibox_output.js b/chrome/browser/resources/omnibox/omnibox_output.js
index 72184d0..53815c5 100644
--- a/chrome/browser/resources/omnibox/omnibox_output.js
+++ b/chrome/browser/resources/omnibox/omnibox_output.js
@@ -8,6 +8,7 @@
    *   cursorPosition: number,
    *   time: number,
    *   done: boolean,
+   *   type: string,
    *   host: string,
    *   isTypedHost: boolean,
    * }}
@@ -31,19 +32,12 @@
       this.responsesHistory = [];
       /** @private {!Array<!OutputResultsGroup>} */
       this.resultsGroups_ = [];
-      /** @private {!QueryInputs} */
-      this.queryInputs_ = /** @type {!QueryInputs} */ ({});
       /** @private {!DisplayInputs} */
       this.displayInputs_ = OmniboxInput.defaultDisplayInputs;
       /** @private {string} */
       this.filterText_ = '';
     }
 
-    /** @param {!QueryInputs} queryInputs */
-    updateQueryInputs(queryInputs) {
-      this.queryInputs_ = queryInputs;
-    }
-
     /** @param {!DisplayInputs} displayInputs */
     updateDisplayInputs(displayInputs) {
       this.displayInputs_ = displayInputs;
@@ -103,8 +97,7 @@
      * @private @param {!mojom.OmniboxResponse} response
      */
     createResultsGroup_(response) {
-      const resultsGroup =
-          OutputResultsGroup.create(response, this.queryInputs_.cursorPosition);
+      const resultsGroup = OutputResultsGroup.create(response);
       this.resultsGroups_.push(resultsGroup);
       this.$$('#contents').appendChild(resultsGroup);
 
@@ -190,12 +183,11 @@
   class OutputResultsGroup extends OmniboxElement {
     /**
      * @param {!mojom.OmniboxResponse} resultsGroup
-     * @param {number} cursorPosition
      * @return {!OutputResultsGroup}
      */
-    static create(resultsGroup, cursorPosition) {
+    static create(resultsGroup) {
       const outputResultsGroup = new OutputResultsGroup();
-      outputResultsGroup.setResultsGroup(resultsGroup, cursorPosition);
+      outputResultsGroup.setResultsGroup(resultsGroup);
       return outputResultsGroup;
     }
 
@@ -203,18 +195,16 @@
       super('output-results-group-template');
     }
 
-    /**
-     *  @param {!mojom.OmniboxResponse} resultsGroup
-     *  @param {number} cursorPosition
-     */
-    setResultsGroup(resultsGroup, cursorPosition) {
+    /** @param {!mojom.OmniboxResponse} resultsGroup */
+    setResultsGroup(resultsGroup) {
       /** @private {ResultsDetails} */
       this.details_ = {
-        cursorPosition: cursorPosition,
+        cursorPosition: resultsGroup.cursorPosition,
         time: resultsGroup.timeSinceOmniboxStartedMs,
         done: resultsGroup.done,
+        type: resultsGroup.type,
         host: resultsGroup.host,
-        isTypedHost: resultsGroup.isTypedHost
+        isTypedHost: resultsGroup.isTypedHost,
       };
       /** @type {!Array<!OutputHeader>} */
       this.headers = COLUMNS.map(OutputHeader.create);
@@ -353,6 +343,7 @@
       this.$$('#cursor-position').textContent = details.cursorPosition;
       this.$$('#time').textContent = details.time;
       this.$$('#done').textContent = details.done;
+      this.$$('#type').textContent = details.type;
       this.$$('#host').textContent = details.host;
       this.$$('#is-typed-host').textContent = details.isTypedHost;
     }
diff --git a/chrome/browser/resources/settings/about_page/about_page.html b/chrome/browser/resources/settings/about_page/about_page.html
index aad7975d..99c0a1c1 100644
--- a/chrome/browser/resources/settings/about_page/about_page.html
+++ b/chrome/browser/resources/settings/about_page/about_page.html
@@ -151,14 +151,19 @@
               </span>
 </if>
 <if expr="chromeos">
-             <div id="endOfLifeMessageContainer" hidden="[[!hasEndOfLife_]]">
-               $i18n{endOfLifeMessage}
-               <a href="$i18n{endOfLifeLearnMoreURL}" target="_blank">
-                 $i18n{learnMore}
-               </a>
-             </div>
+              <div id="endOfLifeMessageContainer" hidden="[[!hasEndOfLife_]]">
+                $i18n{endOfLifeMessage}
+                <a href="$i18n{endOfLifeLearnMoreURL}" target="_blank">
+                  $i18n{learnMore}
+                </a>
+              </div>
 </if>
               <div class="secondary">$i18n{aboutBrowserVersion}</div>
+<if expr="chromeos">
+              <div class="secondary"
+                  inner-h-t-m-l="[[getUpdateOsSettingsLink_()]]">
+              </div>
+</if>
             </div>
             <div class="separator" hidden="[[!showButtonContainer_]]"></div>
             <span id="buttonContainer" hidden="[[!showButtonContainer_]]">
diff --git a/chrome/browser/resources/settings/about_page/about_page.js b/chrome/browser/resources/settings/about_page/about_page.js
index a5c5388..cdb84511 100644
--- a/chrome/browser/resources/settings/about_page/about_page.js
+++ b/chrome/browser/resources/settings/about_page/about_page.js
@@ -632,6 +632,20 @@
         this.i18nAdvanced('aboutProductOsLicense');
   },
 
+  // <if expr="chromeos">
+  /**
+   * @return {string}
+   * @private
+   */
+  getUpdateOsSettingsLink_: function() {
+    // Note: This string contains raw HTML and thus requires i18nAdvanced().
+    // Since the i18n template syntax (e.g., $i18n{}) does not include an
+    // "advanced" version, it's not possible to inline this link directly in the
+    // HTML.
+    return this.i18nAdvanced('aboutUpdateOsSettingsLink');
+  },
+  // </if>
+
   /**
    * @param {boolean} enabled True if Crostini is enabled.
    * @private
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/chrome_app_permission_view.html b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/chrome_app_permission_view.html
index e0a4da9..ef7d836 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/chrome_app_permission_view.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/chrome_app_permission_view.html
@@ -14,11 +14,6 @@
         border-top: none;
       }
 
-      #app-description {
-        padding-bottom: 12px;
-        padding-top: 24px;
-      }
-
       #no-permissions {
         border-top: none;
       }
@@ -29,9 +24,6 @@
 
     </style>
     <div>
-      <div id="app-description" class="permission-card-row">
-        [[app_.description]]
-      </div>
       <div class="permission-list">
         <app-management-pin-to-shelf-item
           id="pin-to-shelf-setting"
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/chrome_app_permission_view.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/chrome_app_permission_view.js
index 4a977be98..cf6bd0b 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/chrome_app_permission_view.js
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/chrome_app_permission_view.js
@@ -36,7 +36,6 @@
     const {messages: messages} =
         await app_management.BrowserProxy.getInstance()
             .handler.getExtensionAppPermissionMessages(this.app_.id);
-    this.$['app-description'].hidden = this.app_.description.length === 0;
     this.messages_ = messages;
   },
 
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/uninstall_button.html b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/uninstall_button.html
index 69749e9..6711f4ee 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/uninstall_button.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/uninstall_button.html
@@ -25,15 +25,17 @@
       <cr-tooltip-icon
           id="policyIndicator"
           icon-class="cr20:domain"
-          tooltip-text="[[getTooltip_(app_)]]"
-          icon-aria-label="[[getTooltip_(app_)]]"
+          tooltip-text="$i18n{policyAppUninstallPolicy}"
+          icon-aria-label="$i18n{policyAppUninstallPolicy}"
           tooltip-position="bottom">
       </cr-tooltip-icon>
     </template>
-    <cr-button id="uninstallButton" on-click="onClick_"
-        disabled$="[[getDisableState_(app_)]]">
-      $i18n{uninstallApp}
-    </cr-button>
+    <template is="dom-if" if="[[showUninstallButton_(app_)]]">
+      <cr-button id="uninstallButton" on-click="onClick_"
+          disabled$="[[getDisableState_(app_)]]">
+        $i18n{uninstallApp}
+      </cr-button>
+    </template>
   </template>
   <script src="uninstall_button.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/uninstall_button.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/uninstall_button.js
index 3b6ce43..40b3629fb 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/uninstall_button.js
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/uninstall_button.js
@@ -6,7 +6,6 @@
   is: 'app-management-uninstall-button',
 
   behaviors: [
-    I18nBehavior,
     app_management.StoreClient,
   ],
 
@@ -50,29 +49,7 @@
   },
 
   /**
-   * Returns string to be shown as a tool tip over the policy indicator.
-   *
-   * @param {App} app
-   * @return {?string}
-   * @private
-   */
-  getTooltip_: function(app) {
-    if (!app) {
-      return '';
-    }
-
-    switch (app.installSource) {
-      case InstallSource.kSystem:
-        return this.i18n('systemAppUninstallPolicy');
-      case InstallSource.kPolicy:
-        return this.i18n('policyAppUninstallPolicy');
-      default:
-        assertNotReached();
-    }
-  },
-
-  /**
-   * Returns true if the app was installed by a policy
+   * Returns true if the app was installed by a policy.
    *
    * @param {App} app
    * @returns {boolean}
@@ -82,8 +59,19 @@
     if (!app) {
       return false;
     }
-    return app.installSource === InstallSource.kPolicy ||
-        app.installSource === InstallSource.kSystem;
+    return app.installSource === InstallSource.kPolicy;
+  },
+
+  /**
+   * Returns true if the uninstall button should be shown.
+   *
+   * @param {App} app
+   */
+  showUninstallButton_: function(app) {
+    if (!app) {
+      return false;
+    }
+    return app.installSource !== InstallSource.kSystem;
   },
 
   /**
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
index 3c93efd..bfdffb2 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -243,6 +243,7 @@
     this.guid = guid;
     // Set default properties until they are loaded.
     this.propertiesReceived_ = false;
+    this.deviceState_ = null;
     this.managedProperties_ = OncMojo.getDefaultManagedProperties(
         OncMojo.getNetworkTypeFromString(type), this.guid, name);
     this.didSetFocus_ = false;
@@ -364,15 +365,10 @@
     if (!this.managedProperties_) {
       return;
     }
+    const type = this.managedProperties_.type;
     this.networkConfig_.getDeviceStateList().then(response => {
-      if (!this.managedProperties_) {
-        return;
-      }
-
       const devices = response.result;
-      this.deviceState_ =
-          devices.find(device => device.type == this.managedProperties_.type) ||
-          null;
+      this.deviceState_ = devices.find(device => device.type == type) || null;
     });
   },
 
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 05dab11..091bb933e 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -753,9 +753,12 @@
       this.initializeRouteFromUrlCalled_ = true;
 
       const route = this.getRouteForPath(window.location.pathname);
-      if (route) {
-        this.recordMetrics(window.location.pathname);
-      }
+
+      // Record all correct paths entered on the settings page, and
+      // as all incorrect paths are routed to the main settings page,
+      // record all incorrect paths as hitting the main settings page.
+      this.recordMetrics(route ? route.path : this.routes_.BASIC.path);
+
       // Never allow direct navigation to ADVANCED.
       if (route && route != this.routes_.ADVANCED) {
         this.currentRoute = route;
diff --git a/chrome/browser/safe_browsing/android/services_delegate_android.cc b/chrome/browser/safe_browsing/android/services_delegate_android.cc
index d3df6e7b..aaf8d5e 100644
--- a/chrome/browser/safe_browsing/android/services_delegate_android.cc
+++ b/chrome/browser/safe_browsing/android/services_delegate_android.cc
@@ -122,14 +122,6 @@
   return telemetry_service_.get();
 }
 
-void ServicesDelegateAndroid::CreateVerdictCacheManager(Profile* profile) {}
-void ServicesDelegateAndroid::RemoveVerdictCacheManager(Profile* profile) {}
-VerdictCacheManager* ServicesDelegateAndroid::GetVerdictCacheManager(
-    Profile* profile) const {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
 void ServicesDelegateAndroid::CreateBinaryUploadService(Profile* profile) {}
 void ServicesDelegateAndroid::RemoveBinaryUploadService(Profile* profile) {}
 BinaryUploadService* ServicesDelegateAndroid::GetBinaryUploadService(
diff --git a/chrome/browser/safe_browsing/android/services_delegate_android.h b/chrome/browser/safe_browsing/android/services_delegate_android.h
index 4329374..0e576c0 100644
--- a/chrome/browser/safe_browsing/android/services_delegate_android.h
+++ b/chrome/browser/safe_browsing/android/services_delegate_android.h
@@ -50,10 +50,6 @@
   void RemoveTelemetryService() override;
   TelemetryService* GetTelemetryService() const override;
 
-  void CreateVerdictCacheManager(Profile* profile) override;
-  void RemoveVerdictCacheManager(Profile* profile) override;
-  VerdictCacheManager* GetVerdictCacheManager(Profile* profile) const override;
-
   void CreateBinaryUploadService(Profile* profile) override;
   void RemoveBinaryUploadService(Profile* profile) override;
   BinaryUploadService* GetBinaryUploadService(Profile* profile) const override;
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index 4352218..14376125 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -896,7 +896,11 @@
     } else {
       // |outcome| is only recorded as succeeded or response_already_cached.
       MaybeLogPasswordReuseLookupResultWithVerdict(
-          web_contents, PasswordType::OTHER_GAIA_PASSWORD,
+          web_contents,
+          password_type.account_type() ==
+                  ReusedPasswordAccountType::SAVED_PASSWORD
+              ? PasswordType::SAVED_PASSWORD
+              : PasswordType::OTHER_GAIA_PASSWORD,
           outcome == RequestOutcome::SUCCEEDED
               ? PasswordReuseLookup::REQUEST_SUCCESS
               : PasswordReuseLookup::CACHE_HIT,
@@ -910,7 +914,8 @@
               content::Referrer(),
               /*in_new_tab=*/true);
       web_contents_with_unhandled_enterprise_reuses_.erase(web_contents);
-    } else {
+    } else if (password_type.account_type() !=
+               ReusedPasswordAccountType::SAVED_PASSWORD) {
       // Opens accounts.google.com in a new tab.
       OpenUrl(web_contents, GetDefaultChangePasswordURL(), content::Referrer(),
               /*in_new_tab=*/true);
@@ -1546,8 +1551,6 @@
           base::RandDouble() <= kProbabilityForSendingReportsFromSafeURLs);
 }
 
-// TODO(crbug.com/995926): Enable caching on Android
-#if BUILDFLAG(FULL_SAFE_BROWSING)
 // Stores |verdict| in |settings| based on its |trigger_type|, |url|,
 // reused |password_type|, |verdict| and |receive_time|.
 void ChromePasswordProtectionService::CacheVerdict(
@@ -1582,6 +1585,7 @@
   return cache_manager_->GetStoredPhishGuardVerdictCount(trigger_type);
 }
 
+#if BUILDFLAG(FULL_SAFE_BROWSING)
 bool ChromePasswordProtectionService::IsUnderAdvancedProtection() {
   return AdvancedProtectionStatusManagerFactory::GetForProfile(profile_)
       ->is_under_advanced_protection();
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.h b/chrome/browser/safe_browsing/chrome_password_protection_service.h
index 45b2175c..84520fa 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.h
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.h
@@ -219,12 +219,6 @@
   LoginReputationClientRequest::PasswordReuseEvent::SyncAccountType
   GetSyncAccountType() const override;
 
-// TODO(crbug.com/995926): Enable caching on Android
-// Note: Before enable verdict cache manager on Android,
-// add CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION to Android
-// Otherwise, it will fail on /components/ content_settings/core/browser/
-// content_settings_default_provider.cc/GetRuleIterator
-#if BUILDFLAG(FULL_SAFE_BROWSING)
   // Stores |verdict| in the cache based on its |trigger_type|, |url|,
   // reused |password_type|, |verdict| and |receive_time|.
   void CacheVerdict(const GURL& url,
@@ -244,7 +238,6 @@
       LoginReputationClientRequest::TriggerType trigger_type,
       ReusedPasswordAccountType password_type,
       LoginReputationClientResponse* out_response) override;
-#endif
 
   // Sanitize referrer chain by only keeping origin information of all URLs.
   void SanitizeReferrerChain(ReferrerChain* referrer_chain) override;
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
index 0f5b01c..8093791 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
@@ -103,10 +103,6 @@
   if (result != BinaryUploadService::Result::SUCCESS)
     return;
 
-  if (!g_browser_process->local_state()->GetBoolean(
-          prefs::kUnsafeEventsReportingEnabled))
-    return;
-
   if (response.malware_scan_verdict().verdict() ==
           MalwareDeepScanningVerdict::UWS ||
       response.malware_scan_verdict().verdict() ==
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index 6b085929..e000c6c 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -118,7 +118,7 @@
     argv.push_back(kXdgSettingsDefaultSchemeHandler);
     argv.push_back(protocol);
   }
-  argv.push_back(GetDesktopName(env.get()));
+  argv.push_back(chrome::GetDesktopName(env.get()));
 
   int exit_code;
   bool ran_ok = LaunchXdgUtility(argv, &exit_code);
@@ -154,7 +154,7 @@
     argv.push_back(kXdgSettingsDefaultSchemeHandler);
     argv.push_back(protocol);
   }
-  argv.push_back(GetDesktopName(env.get()));
+  argv.push_back(chrome::GetDesktopName(env.get()));
 
   std::string reply;
   int success_code;
@@ -407,35 +407,13 @@
 std::string GetProgramClassName() {
   std::unique_ptr<base::Environment> env(base::Environment::Create());
   return internal::GetProgramClassName(*base::CommandLine::ForCurrentProcess(),
-                                       GetDesktopName(env.get()));
+                                       chrome::GetDesktopName(env.get()));
 }
 
 std::string GetProgramClassClass() {
   std::unique_ptr<base::Environment> env(base::Environment::Create());
   return internal::GetProgramClassClass(*base::CommandLine::ForCurrentProcess(),
-                                        GetDesktopName(env.get()));
-}
-
-std::string GetDesktopName(base::Environment* env) {
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-  version_info::Channel product_channel(chrome::GetChannel());
-  switch (product_channel) {
-    case version_info::Channel::DEV:
-      return "google-chrome-unstable.desktop";
-    case version_info::Channel::BETA:
-      return "google-chrome-beta.desktop";
-    default:
-      return "google-chrome.desktop";
-  }
-#else  // BUILDFLAG(CHROMIUM_BRANDING)
-  // Allow $CHROME_DESKTOP to override the built-in value, so that development
-  // versions can set themselves as the default without interfering with
-  // non-official, packaged versions using the built-in value.
-  std::string name;
-  if (env->GetVar("CHROME_DESKTOP", &name) && !name.empty())
-    return name;
-  return "chromium-browser.desktop";
-#endif
+                                        chrome::GetDesktopName(env.get()));
 }
 
 std::string GetIconName() {
diff --git a/chrome/browser/shell_integration_linux.h b/chrome/browser/shell_integration_linux.h
index 0714226a..ebd4b6d 100644
--- a/chrome/browser/shell_integration_linux.h
+++ b/chrome/browser/shell_integration_linux.h
@@ -35,9 +35,6 @@
 // Gets the name for use as the res_class of the window's WM_CLASS property.
 std::string GetProgramClassClass();
 
-// Returns filename of the desktop shortcut used to launch the browser.
-std::string GetDesktopName(base::Environment* env);
-
 // Returns name of the browser icon (without a path or file extension).
 std::string GetIconName();
 
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc
index 9a1452cd..9090a743 100644
--- a/chrome/browser/signin/signin_ui_util.cc
+++ b/chrome/browser/signin/signin_ui_util.cc
@@ -8,10 +8,14 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/feature_list.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/supports_user_data.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
@@ -42,8 +46,64 @@
 #include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h"
 #endif
 
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
 namespace {
+
+// Key for storing animated identity per-profile data.
+const char kAnimatedIdentityKeyName[] = "animated_identity_user_data";
+
+constexpr base::TimeDelta kDelayForCrossWindowAnimationReplay =
+    base::TimeDelta::FromSeconds(5);
+
+// UserData attached to the user profile, keeping track of the last time the
+// animation was shown to the user.
+class AnimatedIdentityUserData : public base::SupportsUserData::Data {
+ public:
+  ~AnimatedIdentityUserData() override = default;
+
+  // Returns the  last time the animation was shown. Returns the null time if it
+  // was never shown.
+  static base::TimeTicks GetLastShown(Profile* profile) {
+    DCHECK(profile);
+    AnimatedIdentityUserData* data = GetForProfile(profile);
+    if (!data)
+      return base::TimeTicks();
+
+    DCHECK(!data->last_shown_.is_null());
+    return data->last_shown_;
+  }
+
+  // Sets the animation time.
+  static void SetLastShown(Profile* profile, base::TimeTicks time) {
+    DCHECK(!time.is_null());
+    GetOrCreateForProfile(profile)->last_shown_ = time;
+  }
+
+ private:
+  // Returns nullptr if there is no AnimatedIdentityUserData attached to the
+  // profile.
+  static AnimatedIdentityUserData* GetForProfile(Profile* profile) {
+    return static_cast<AnimatedIdentityUserData*>(
+        profile->GetUserData(kAnimatedIdentityKeyName));
+  }
+
+  // Never returns nullptr.
+  static AnimatedIdentityUserData* GetOrCreateForProfile(Profile* profile) {
+    DCHECK(profile);
+    AnimatedIdentityUserData* existing_data = GetForProfile(profile);
+    if (existing_data)
+      return existing_data;
+
+    auto new_data = std::make_unique<AnimatedIdentityUserData>();
+    auto* new_data_ptr = new_data.get();
+    profile->SetUserData(kAnimatedIdentityKeyName, std::move(new_data));
+    return new_data_ptr;
+  }
+
+  // Last time the animation was shown.
+  base::TimeTicks last_shown_;
+};
+
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
 void CreateDiceTurnSyncOnHelper(
     Profile* profile,
     Browser* browser,
@@ -58,9 +118,10 @@
                            signin_promo_action, signin_reason, account_id,
                            signin_aborted_mode);
 }
-}  // namespace
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
+}  // namespace
+
 namespace signin_ui_util {
 
 base::string16 GetAuthenticatedUsername(Profile* profile) {
@@ -270,20 +331,22 @@
   return domain;
 }
 
-bool ShouldShowIdentityOnOpeningProfile(
+bool ShouldShowAnimatedIdentityOnOpeningWindow(
     const ProfileAttributesStorage& profile_attributes_storage,
     Profile* profile) {
   DCHECK(profile);
   signin::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile);
   DCHECK(identity_manager->AreRefreshTokensLoaded());
-  // Wait with the potential positive response until refresh tokens are loaded
-  // so that we never show it twice on startup.
-  // TODO(crbug.com/1009441): Make it only appear once per profile
-  // instantiation (currently it appears for every new window which have their
-  // own instance of AvatarToolbarButton).
-  if (!base::FeatureList::IsEnabled(
-          features::kAnimatedAvatarButtonOnOpeningProfile)) {
+
+  base::TimeTicks animation_last_shown =
+      AnimatedIdentityUserData::GetLastShown(profile);
+  // When a new window is created, only show the animation if it was never shown
+  // for this profile, or if it was shown in another window in the last few
+  // seconds (because the user may have missed it).
+  if (!animation_last_shown.is_null() &&
+      base::TimeTicks::Now() - animation_last_shown >
+          kDelayForCrossWindowAnimationReplay) {
     return false;
   }
 
@@ -296,4 +359,20 @@
   return identity_manager->GetAccountsWithRefreshTokens().size() > 1;
 }
 
+void RecordAnimatedIdentityTriggered(Profile* profile) {
+  AnimatedIdentityUserData::SetLastShown(profile, base::TimeTicks::Now());
+}
+
+void RecordProfileMenuViewShown(Profile* profile) {
+  base::RecordAction(base::UserMetricsAction("ProfileMenu_Opened"));
+
+  base::TimeTicks animation_last_shown =
+      AnimatedIdentityUserData::GetLastShown(profile);
+  if (animation_last_shown.is_null())
+    return;
+
+  base::UmaHistogramLongTimes("Profile.Menu.OpenedAfterAvatarAnimation",
+                              base::TimeTicks::Now() - animation_last_shown);
+}
+
 }  // namespace signin_ui_util
diff --git a/chrome/browser/signin/signin_ui_util.h b/chrome/browser/signin/signin_ui_util.h
index ca329ae..807c5508 100644
--- a/chrome/browser/signin/signin_ui_util.h
+++ b/chrome/browser/signin/signin_ui_util.h
@@ -96,12 +96,19 @@
 #endif
 
 // Returns whether Chrome should show the identity of the user (using a brief
-// animation) on opening a profile. IdentityManager's refresh tokens must be
+// animation) on opening a new window. IdentityManager's refresh tokens must be
 // loaded when this function gets called.
-bool ShouldShowIdentityOnOpeningProfile(
+bool ShouldShowAnimatedIdentityOnOpeningWindow(
     const ProfileAttributesStorage& profile_attributes_storage,
     Profile* profile);
 
+// Records that the animated identity was shown for the given profile. This is
+// used for metrics and to decide whether/when the animation can be shown again.
+void RecordAnimatedIdentityTriggered(Profile* profile);
+
+// Called when the ProfileMenuView is opened. Used for metrics.
+void RecordProfileMenuViewShown(Profile* profile);
+
 }  // namespace signin_ui_util
 
 #endif  // CHROME_BROWSER_SIGNIN_SIGNIN_UI_UTIL_H_
diff --git a/chrome/browser/signin/signin_ui_util_unittest.cc b/chrome/browser/signin/signin_ui_util_unittest.cc
index 8a42342..f2ea790 100644
--- a/chrome/browser/signin/signin_ui_util_unittest.cc
+++ b/chrome/browser/signin/signin_ui_util_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
+#include "base/test/task_environment.h"
 #include "build/buildflag.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
@@ -89,7 +90,9 @@
 
 class DiceSigninUiUtilTest : public BrowserWithTestWindowTest {
  public:
-  DiceSigninUiUtilTest() = default;
+  DiceSigninUiUtilTest()
+      : BrowserWithTestWindowTest(
+            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
   ~DiceSigninUiUtilTest() override = default;
 
   struct CreateDiceTurnSyncOnHelperParams {
@@ -508,7 +511,7 @@
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
 TEST_F(DiceSigninUiUtilTest,
-       ShouldShowIdentityOnOpeningProfile_ReturnsTrueForMultiProfiles) {
+       ShouldShowAnimatedIdentityOnOpeningWindow_ReturnsTrueForMultiProfiles) {
   const char kSecondProfile[] = "SecondProfile";
   const base::FilePath profile_path =
       profile_manager()->profiles_dir().AppendASCII(kSecondProfile);
@@ -516,12 +519,12 @@
       profile_path, base::ASCIIToUTF16(kSecondProfile), std::string(),
       base::string16(), false, 0, std::string(), EmptyAccountId());
 
-  EXPECT_TRUE(ShouldShowIdentityOnOpeningProfile(
+  EXPECT_TRUE(ShouldShowAnimatedIdentityOnOpeningWindow(
       *profile_manager()->profile_attributes_storage(), profile()));
 }
 
 TEST_F(DiceSigninUiUtilTest,
-       ShouldShowIdentityOnOpeningProfile_ReturnsTrueForMultiSignin) {
+       ShouldShowAnimatedIdentityOnOpeningWindow_ReturnsTrueForMultiSignin) {
   GetIdentityManager()->GetAccountsMutator()->AddOrUpdateAccount(
       kMainGaiaID, kMainEmail, "refresh_token", false,
       signin_metrics::SourceForRefreshTokenOperation::kUnknown);
@@ -529,36 +532,46 @@
       kSecondaryEmail, kSecondaryGaiaID, "refresh_token", false,
       signin_metrics::SourceForRefreshTokenOperation::kUnknown);
 
-  EXPECT_TRUE(ShouldShowIdentityOnOpeningProfile(
+  EXPECT_TRUE(ShouldShowAnimatedIdentityOnOpeningWindow(
+      *profile_manager()->profile_attributes_storage(), profile()));
+
+  // The identity can be shown again immediately (which is what happens if there
+  // is multiple windows at startup).
+  RecordAnimatedIdentityTriggered(profile());
+  EXPECT_TRUE(ShouldShowAnimatedIdentityOnOpeningWindow(
       *profile_manager()->profile_attributes_storage(), profile()));
 }
 
 TEST_F(
     DiceSigninUiUtilTest,
-    ShouldShowIdentityOnOpeningProfile_ReturnsFalseForSingleProfileSingleSignin) {
+    ShouldShowAnimatedIdentityOnOpeningWindow_ReturnsFalseForSingleProfileSingleSignin) {
   GetIdentityManager()->GetAccountsMutator()->AddOrUpdateAccount(
       kMainGaiaID, kMainEmail, "refresh_token", false,
       signin_metrics::SourceForRefreshTokenOperation::kUnknown);
 
-  EXPECT_FALSE(ShouldShowIdentityOnOpeningProfile(
+  EXPECT_FALSE(ShouldShowAnimatedIdentityOnOpeningWindow(
       *profile_manager()->profile_attributes_storage(), profile()));
 }
 
 TEST_F(DiceSigninUiUtilTest,
-       ShouldShowIdentityOnOpeningProfile_ReturnsFalseForFeatureDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      features::kAnimatedAvatarButtonOnOpeningProfile);
-
-  // Do the same setup that makes the previous test return true.
+       ShouldShowAnimatedIdentityOnOpeningWindow_ReturnsFalseForNewWindow) {
   GetIdentityManager()->GetAccountsMutator()->AddOrUpdateAccount(
       kMainGaiaID, kMainEmail, "refresh_token", false,
       signin_metrics::SourceForRefreshTokenOperation::kUnknown);
   GetIdentityManager()->GetAccountsMutator()->AddOrUpdateAccount(
       kSecondaryEmail, kSecondaryGaiaID, "refresh_token", false,
       signin_metrics::SourceForRefreshTokenOperation::kUnknown);
+  EXPECT_TRUE(ShouldShowAnimatedIdentityOnOpeningWindow(
+      *profile_manager()->profile_attributes_storage(), profile()));
 
-  EXPECT_FALSE(ShouldShowIdentityOnOpeningProfile(
+  // Animation is shown once.
+  RecordAnimatedIdentityTriggered(profile());
+
+  // Wait a few seconds.
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(6));
+
+  // Animation is not shown again in a new window.
+  EXPECT_FALSE(ShouldShowAnimatedIdentityOnOpeningWindow(
       *profile_manager()->profile_attributes_storage(), profile()));
 }
 
diff --git a/chrome/browser/signin/signin_util_win.cc b/chrome/browser/signin/signin_util_win.cc
index 13b63e5..dcf3887a 100644
--- a/chrome/browser/signin/signin_util_win.cc
+++ b/chrome/browser/signin/signin_util_win.cc
@@ -14,6 +14,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/registry.h"
 #include "base/win/win_util.h"
+#include "base/win/wincrypt_shim.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/profiles/profile.h"
@@ -25,7 +26,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
-#include "components/os_crypt/os_crypt.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/about_signin_internals.h"
 #include "components/signin/public/base/signin_metrics.h"
@@ -45,10 +45,20 @@
 }
 
 std::string DecryptRefreshToken(const std::string& cipher_text) {
-  std::string refresh_token;
-  if (!OSCrypt::DecryptString(cipher_text, &refresh_token))
+  DATA_BLOB input;
+  input.pbData =
+      const_cast<BYTE*>(reinterpret_cast<const BYTE*>(cipher_text.data()));
+  input.cbData = static_cast<DWORD>(cipher_text.length());
+  DATA_BLOB output;
+  BOOL result = ::CryptUnprotectData(&input, nullptr, nullptr, nullptr, nullptr,
+                                     CRYPTPROTECT_UI_FORBIDDEN, &output);
+
+  if (!result)
     return std::string();
 
+  std::string refresh_token(reinterpret_cast<char*>(output.pbData),
+                            output.cbData);
+  ::LocalFree(output.pbData);
   return refresh_token;
 }
 
diff --git a/chrome/browser/signin/signin_util_win_browsertest.cc b/chrome/browser/signin/signin_util_win_browsertest.cc
index d367ecd..a2eed3c 100644
--- a/chrome/browser/signin/signin_util_win_browsertest.cc
+++ b/chrome/browser/signin/signin_util_win_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/test_reg_util_win.h"
+#include "base/win/wincrypt_shim.h"
 #include "build/build_config.h"
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -24,7 +25,6 @@
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_browser_process.h"
-#include "components/os_crypt/os_crypt.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/base/signin_pref_names.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -110,7 +110,7 @@
     }
 
     if (!GetParam().refresh_token.empty())
-      WriteRrefreshToken(&key, GetParam().refresh_token);
+      WriteRefreshToken(&key, GetParam().refresh_token);
 
     if (GetParam().expect_is_started) {
       signin_util::SetDiceTurnSyncOnHelperDelegateForTesting(
@@ -132,16 +132,26 @@
     }
   }
 
-  void WriteRrefreshToken(base::win::RegKey* key,
-                          const std::string& refresh_token) {
+  void WriteRefreshToken(base::win::RegKey* key,
+                         const std::string& refresh_token) {
     EXPECT_TRUE(key->Valid());
-    std::string ciphertext;
-    EXPECT_TRUE(OSCrypt::EncryptString(refresh_token, &ciphertext));
+    DATA_BLOB plaintext;
+    plaintext.pbData =
+        reinterpret_cast<BYTE*>(const_cast<char*>(refresh_token.c_str()));
+    plaintext.cbData = static_cast<DWORD>(refresh_token.length());
+
+    DATA_BLOB ciphertext;
+    ASSERT_TRUE(::CryptProtectData(&plaintext, L"Gaia refresh token", nullptr,
+                                   nullptr, nullptr, CRYPTPROTECT_UI_FORBIDDEN,
+                                   &ciphertext));
+    std::string encrypted_data(reinterpret_cast<char*>(ciphertext.pbData),
+                               ciphertext.cbData);
     EXPECT_EQ(
         ERROR_SUCCESS,
         key->WriteValue(
             base::ASCIIToUTF16(credential_provider::kKeyRefreshToken).c_str(),
-            ciphertext.c_str(), ciphertext.length(), REG_BINARY));
+            encrypted_data.c_str(), encrypted_data.length(), REG_BINARY));
+    LocalFree(ciphertext.pbData);
   }
 
   void ExpectRefreshTokenExists(bool exists) {
@@ -205,7 +215,7 @@
     // Write a new refresh token.
     base::win::RegKey key;
     CreateRegKey(&key);
-    WriteRrefreshToken(&key, "lst-new");
+    WriteRefreshToken(&key, "lst-new");
     ASSERT_FALSE(signin_util::ReauthWithCredentialProviderIfPossible(profile));
 
     // Sign user out of browser.
@@ -234,7 +244,7 @@
     // Write a new refresh token. This time reauth should work.
     base::win::RegKey key;
     CreateRegKey(&key);
-    WriteRrefreshToken(&key, "lst-new");
+    WriteRefreshToken(&key, "lst-new");
     ASSERT_FALSE(signin_util::ReauthWithCredentialProviderIfPossible(profile));
 
     // Make sure the profile stays signed in, but in an auth error state.
diff --git a/chrome/browser/site_isolation/site_isolation_policy.cc b/chrome/browser/site_isolation/site_isolation_policy.cc
index d15ee29c..69c2be7 100644
--- a/chrome/browser/site_isolation/site_isolation_policy.cc
+++ b/chrome/browser/site_isolation/site_isolation_policy.cc
@@ -16,9 +16,23 @@
 
 // static
 bool SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled() {
-  // Ignore attempts to add new isolated origins when site isolation is turned
-  // off, for example via a command-line switch, or via a content/ embedder
-  // that turns site isolation off for low-memory devices.
+  // If the user has explicitly enabled site isolation for password sites from
+  // chrome://flags or from the command line, honor this regardless of policies
+  // that may disable site isolation.  In particular, this means that the
+  // chrome://flags switch for this feature takes precedence over any memory
+  // threshold restrictions and over a switch for disabling site isolation.
+  if (base::FeatureList::GetInstance()->IsFeatureOverriddenFromCommandLine(
+          features::kSiteIsolationForPasswordSites.name,
+          base::FeatureList::OVERRIDE_ENABLE_FEATURE)) {
+    return true;
+  }
+
+  // Don't isolate anything when site isolation is turned off by the user or
+  // policy. This includes things like the switches::kDisableSiteIsolation
+  // command-line switch, the corresponding "Disable site isolation" entry in
+  // chrome://flags, enterprise policy controlled via
+  // switches::kDisableSiteIsolationForPolicy, and memory threshold checks in
+  // ShouldDisableSiteIsolationDueToMemoryThreshold().
   if (!content::SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled())
     return false;
 
@@ -43,6 +57,34 @@
 }
 
 // static
+bool SiteIsolationPolicy::ShouldDisableSiteIsolationDueToMemoryThreshold() {
+  // Using 1077 rather than 1024 because 1) it helps ensure that devices with
+  // exactly 1GB of RAM won't get included because of inaccuracies or off-by-one
+  // errors and 2) this is the bucket boundary in Memory.Stats.Win.TotalPhys2.
+  // See also https://crbug.com/844118.
+  constexpr int kDefaultMemoryThresholdMb = 1077;
+
+  // TODO(acolwell): Rename feature since it now affects more than just the
+  // site-per-process case.
+  if (base::FeatureList::IsEnabled(
+          features::kSitePerProcessOnlyForHighMemoryClients)) {
+    int memory_threshold_mb = base::GetFieldTrialParamByFeatureAsInt(
+        features::kSitePerProcessOnlyForHighMemoryClients,
+        features::kSitePerProcessOnlyForHighMemoryClientsParamName,
+        kDefaultMemoryThresholdMb);
+    return base::SysInfo::AmountOfPhysicalMemoryMB() <= memory_threshold_mb;
+  }
+
+#if defined(OS_ANDROID)
+  if (base::SysInfo::AmountOfPhysicalMemoryMB() <= kDefaultMemoryThresholdMb) {
+    return true;
+  }
+#endif
+
+  return false;
+}
+
+// static
 void SiteIsolationPolicy::ApplyPersistedIsolatedOrigins(Profile* profile) {
   // If the user turned off password-triggered isolation, don't apply any
   // stored isolated origins, but also don't clear them from prefs, so that
diff --git a/chrome/browser/site_isolation/site_isolation_policy.h b/chrome/browser/site_isolation/site_isolation_policy.h
index 6183546..25dd216 100644
--- a/chrome/browser/site_isolation/site_isolation_policy.h
+++ b/chrome/browser/site_isolation/site_isolation_policy.h
@@ -31,6 +31,15 @@
   // have been loaded.
   static void ApplyPersistedIsolatedOrigins(Profile* profile);
 
+  // Determines whether Site Isolation should be disabled because the device
+  // does not have the minimum required amount of memory.
+  //
+  // TODO(alexmos): Currently, the memory threshold is shared for all site
+  // isolation modes, including strict site isolation and password site
+  // isolation.  In the future, some site isolation modes may require their own
+  // memory threshold.
+  static bool ShouldDisableSiteIsolationDueToMemoryThreshold();
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(SiteIsolationPolicy);
 };
diff --git a/chrome/browser/ssl/ssl_config_service_manager_pref.cc b/chrome/browser/ssl/ssl_config_service_manager_pref.cc
index 361e12b..98991f1e 100644
--- a/chrome/browser/ssl/ssl_config_service_manager_pref.cc
+++ b/chrome/browser/ssl/ssl_config_service_manager_pref.cc
@@ -10,11 +10,12 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "components/content_settings/core/browser/content_settings_utils.h"
@@ -150,6 +151,7 @@
   // The local_state prefs.
   BooleanPrefMember rev_checking_enabled_;
   BooleanPrefMember rev_checking_required_local_anchors_;
+  BooleanPrefMember tls13_hardening_for_local_anchors_enabled_;
   StringPrefMember ssl_version_min_;
   StringPrefMember ssl_version_max_;
   StringListPrefMember h2_client_cert_coalescing_host_patterns_;
@@ -166,6 +168,11 @@
     PrefService* local_state) {
   DCHECK(local_state);
 
+  local_state->SetDefaultPrefValue(
+      prefs::kTLS13HardeningForLocalAnchorsEnabled,
+      base::Value(base::FeatureList::IsEnabled(
+          features::kTLS13HardeningForLocalAnchors)));
+
   PrefChangeRegistrar::NamedChangeCallback local_state_callback =
       base::BindRepeating(&SSLConfigServiceManagerPref::OnPreferenceChanged,
                           base::Unretained(this), local_state);
@@ -175,6 +182,9 @@
   rev_checking_required_local_anchors_.Init(
       prefs::kCertRevocationCheckingRequiredLocalAnchors, local_state,
       local_state_callback);
+  tls13_hardening_for_local_anchors_enabled_.Init(
+      prefs::kTLS13HardeningForLocalAnchorsEnabled, local_state,
+      local_state_callback);
   ssl_version_min_.Init(prefs::kSSLVersionMin, local_state,
                         local_state_callback);
   ssl_version_max_.Init(prefs::kSSLVersionMax, local_state,
@@ -198,6 +208,10 @@
   registry->RegisterBooleanPref(
       prefs::kCertRevocationCheckingRequiredLocalAnchors,
       default_verifier_config.require_rev_checking_local_anchors);
+  net::SSLContextConfig default_context_config;
+  registry->RegisterBooleanPref(
+      prefs::kTLS13HardeningForLocalAnchorsEnabled,
+      default_context_config.tls13_hardening_for_local_anchors_enabled);
   registry->RegisterStringPref(prefs::kSSLVersionMin, std::string());
   registry->RegisterStringPref(prefs::kSSLVersionMax, std::string());
   registry->RegisterListPref(prefs::kCipherSuiteBlacklist);
@@ -247,6 +261,8 @@
     config->rev_checking_enabled = false;
   config->rev_checking_required_local_anchors =
       rev_checking_required_local_anchors_.GetValue();
+  config->tls13_hardening_for_local_anchors_enabled =
+      tls13_hardening_for_local_anchors_enabled_.GetValue();
   std::string version_min_str = ssl_version_min_.GetValue();
   std::string version_max_str = ssl_version_max_.GetValue();
 
diff --git a/chrome/browser/ssl/ssl_config_service_manager_pref_unittest.cc b/chrome/browser/ssl/ssl_config_service_manager_pref_unittest.cc
index 9b9b453..7d5def8 100644
--- a/chrome/browser/ssl/ssl_config_service_manager_pref_unittest.cc
+++ b/chrome/browser/ssl/ssl_config_service_manager_pref_unittest.cc
@@ -6,11 +6,14 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/values.h"
 #include "chrome/browser/ssl/ssl_config_service_manager.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/testing_pref_service.h"
@@ -297,3 +300,57 @@
 
   EXPECT_TRUE(observed_configs_[0]->rev_checking_required_local_anchors);
 }
+
+// Tests that the TLS 1.3 hardening pref correctly sets the corresponding value
+// in SSL configs.
+TEST_F(SSLConfigServiceManagerPrefTest, TLS13HardeningForLocalAnchors) {
+  TestingPrefServiceSimple local_state;
+  SSLConfigServiceManager::RegisterPrefs(local_state.registry());
+
+  std::unique_ptr<SSLConfigServiceManager> config_manager =
+      SetUpConfigServiceManager(&local_state);
+
+  // The hardening is disabled by default.
+  EXPECT_FALSE(initial_config_->tls13_hardening_for_local_anchors_enabled);
+
+  // It can be enabled via preference.
+  local_state.SetUserPref(prefs::kTLS13HardeningForLocalAnchorsEnabled,
+                          std::make_unique<base::Value>(true));
+  ASSERT_NO_FATAL_FAILURE(WaitForUpdate());
+  EXPECT_TRUE(observed_configs_[0]->tls13_hardening_for_local_anchors_enabled);
+
+  // It can then be disabled again.
+  local_state.SetUserPref(prefs::kTLS13HardeningForLocalAnchorsEnabled,
+                          std::make_unique<base::Value>(false));
+  ASSERT_NO_FATAL_FAILURE(WaitForUpdate());
+  EXPECT_FALSE(observed_configs_[1]->tls13_hardening_for_local_anchors_enabled);
+}
+
+// Tests that the TLS 1.3 hardening pref correctly interacts with the feature
+// flag.
+TEST_F(SSLConfigServiceManagerPrefTest,
+       TLS13HardeningForLocalAnchorsFeatureEnabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kTLS13HardeningForLocalAnchors);
+
+  TestingPrefServiceSimple local_state;
+  SSLConfigServiceManager::RegisterPrefs(local_state.registry());
+
+  std::unique_ptr<SSLConfigServiceManager> config_manager =
+      SetUpConfigServiceManager(&local_state);
+
+  // With the feature enabled, the hardening is enabled by default.
+  EXPECT_TRUE(initial_config_->tls13_hardening_for_local_anchors_enabled);
+
+  // It can be disabled via preferences.
+  local_state.SetUserPref(prefs::kTLS13HardeningForLocalAnchorsEnabled,
+                          std::make_unique<base::Value>(false));
+  ASSERT_NO_FATAL_FAILURE(WaitForUpdate());
+  EXPECT_FALSE(observed_configs_[0]->tls13_hardening_for_local_anchors_enabled);
+
+  // It can then be enabled again.
+  local_state.SetUserPref(prefs::kTLS13HardeningForLocalAnchorsEnabled,
+                          std::make_unique<base::Value>(true));
+  ASSERT_NO_FATAL_FAILURE(WaitForUpdate());
+  EXPECT_TRUE(observed_configs_[1]->tls13_hardening_for_local_anchors_enabled);
+}
diff --git a/chrome/browser/supervised_user/permission_request_creator_mock.cc b/chrome/browser/supervised_user/permission_request_creator_mock.cc
new file mode 100644
index 0000000..5e25e05
--- /dev/null
+++ b/chrome/browser/supervised_user/permission_request_creator_mock.cc
@@ -0,0 +1,113 @@
+// 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/supervised_user/permission_request_creator_mock.h"
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/supervised_user/supervised_user_constants.h"
+#include "chrome/browser/supervised_user/supervised_user_settings_service.h"
+#include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
+
+namespace {
+
+std::unique_ptr<base::DictionaryValue> GetManualBehaviorHostDict(
+    Profile* profile) {
+  SupervisedUserSettingsService* settings_service =
+      SupervisedUserSettingsServiceFactory::GetForKey(profile->GetProfileKey());
+  const base::DictionaryValue* local_settings =
+      settings_service->LocalSettingsForTest();
+  std::unique_ptr<base::DictionaryValue> dict_to_insert;
+
+  if (local_settings->HasKey(
+          supervised_users::kContentPackManualBehaviorHosts)) {
+    const base::DictionaryValue* dict_value;
+
+    local_settings->GetDictionary(
+        supervised_users::kContentPackManualBehaviorHosts, &dict_value);
+
+    std::unique_ptr<base::Value> clone =
+        std::make_unique<base::Value>(dict_value->Clone());
+
+    dict_to_insert = base::DictionaryValue::From(std::move(clone));
+  } else {
+    dict_to_insert = std::make_unique<base::DictionaryValue>();
+  }
+
+  return dict_to_insert;
+}
+
+}  // namespace
+
+PermissionRequestCreatorMock::PermissionRequestCreatorMock(Profile* profile)
+    : profile_(profile) {}
+
+PermissionRequestCreatorMock::~PermissionRequestCreatorMock() = default;
+
+bool PermissionRequestCreatorMock::IsEnabled() const {
+  return enabled_;
+}
+
+void PermissionRequestCreatorMock::CreateURLAccessRequest(
+    const GURL& url_requested,
+    SuccessCallback callback) {
+  DCHECK(enabled_);
+  url_requests_.push_back(url_requested);
+  if (!delay_handling_)
+    CreateURLAccessRequestImpl(url_requested);
+  std::move(callback).Run(true);
+}
+
+void PermissionRequestCreatorMock::SetPermissionResult(bool result) {
+  result_ = result;
+}
+
+void PermissionRequestCreatorMock::SetEnabled() {
+  enabled_ = true;
+}
+
+void PermissionRequestCreatorMock::DelayHandlingForNextRequests() {
+  DCHECK(!delay_handling_);
+
+  last_url_request_handled_index_ = url_requests_.size() - 1;
+  delay_handling_ = true;
+}
+
+void PermissionRequestCreatorMock::HandleDelayedRequests() {
+  DCHECK(delay_handling_);
+
+  auto dict_to_insert = GetManualBehaviorHostDict(profile_);
+
+  for (size_t i = last_url_request_handled_index_ + 1; i < url_requests_.size();
+       i++) {
+    dict_to_insert->SetKey(url_requests_[i].host(), base::Value(result_));
+  }
+
+  SupervisedUserSettingsService* settings_service =
+      SupervisedUserSettingsServiceFactory::GetForKey(
+          profile_->GetProfileKey());
+
+  settings_service->SetLocalSetting(
+      supervised_users::kContentPackManualBehaviorHosts,
+      std::move(dict_to_insert));
+
+  delay_handling_ = false;
+}
+
+void PermissionRequestCreatorMock::CreateURLAccessRequestImpl(
+    const GURL& url_requested) {
+  auto dict_to_insert = GetManualBehaviorHostDict(profile_);
+  dict_to_insert->SetKey(url_requested.host(), base::Value(result_));
+
+  SupervisedUserSettingsService* settings_service =
+      SupervisedUserSettingsServiceFactory::GetForKey(
+          profile_->GetProfileKey());
+  settings_service->SetLocalSetting(
+      supervised_users::kContentPackManualBehaviorHosts,
+      std::move(dict_to_insert));
+}
diff --git a/chrome/browser/supervised_user/permission_request_creator_mock.h b/chrome/browser/supervised_user/permission_request_creator_mock.h
new file mode 100644
index 0000000..7946b53d
--- /dev/null
+++ b/chrome/browser/supervised_user/permission_request_creator_mock.h
@@ -0,0 +1,54 @@
+// 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_SUPERVISED_USER_PERMISSION_REQUEST_CREATOR_MOCK_H_
+#define CHROME_BROWSER_SUPERVISED_USER_PERMISSION_REQUEST_CREATOR_MOCK_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "chrome/browser/supervised_user/permission_request_creator.h"
+#include "url/gurl.h"
+
+class Profile;
+
+class PermissionRequestCreatorMock : public PermissionRequestCreator {
+ public:
+  explicit PermissionRequestCreatorMock(Profile* profile);
+  ~PermissionRequestCreatorMock() override;
+
+  // PermissionRequestCreator:
+  bool IsEnabled() const override;
+  void CreateURLAccessRequest(const GURL& url_requested,
+                              SuccessCallback callback) override;
+
+  // Sets whether the next call to create requests will succeed.
+  void SetPermissionResult(bool result);
+  void SetEnabled();
+
+  // Delays approvals for incoming requests until
+  // |PermissionRequestCreatorMock::HandleDelayedRequests| is called.
+  void DelayHandlingForNextRequests();
+  void HandleDelayedRequests();
+
+  // Getter methods.
+  const std::vector<GURL>& url_requests() const { return url_requests_; }
+
+ private:
+  void CreateURLAccessRequestImpl(const GURL& url_requested);
+
+  bool result_ = false;
+  bool enabled_ = false;
+  bool delay_handling_ = false;
+  int last_url_request_handled_index_ = 0;
+
+  Profile* profile_ = nullptr;
+
+  std::vector<GURL> url_requests_;
+
+  DISALLOW_COPY_AND_ASSIGN(PermissionRequestCreatorMock);
+};
+
+#endif  // CHROME_BROWSER_SUPERVISED_USER_PERMISSION_REQUEST_CREATOR_MOCK_H_
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.cc b/chrome/browser/supervised_user/supervised_user_interstitial.cc
index 0d2f394..68c59e05 100644
--- a/chrome/browser/supervised_user/supervised_user_interstitial.cc
+++ b/chrome/browser/supervised_user/supervised_user_interstitial.cc
@@ -54,6 +54,15 @@
 // For use in histograms.
 enum Commands { PREVIEW, BACK, NTP, ACCESS_REQUEST, HISTOGRAM_BOUNDING_VALUE };
 
+// For use in histograms.The enum values should remain synchronized with the
+// enum ManagedUserURLRequestPermissionSource in
+// tools/metrics/histograms/enums.xml.
+enum class RequestPermissionSource {
+  MAIN_FRAME = 0,
+  SUB_FRAME,
+  HISTOGRAM_BOUNDING_VALUE
+};
+
 class TabCloser : public content::WebContentsUserData<TabCloser> {
  public:
   ~TabCloser() override {}
@@ -139,11 +148,15 @@
 std::unique_ptr<SupervisedUserInterstitial> SupervisedUserInterstitial::Create(
     WebContents* web_contents,
     const GURL& url,
-    supervised_user_error_page::FilteringBehaviorReason reason) {
-  std::unique_ptr<SupervisedUserInterstitial> interstitial = base::WrapUnique(
-      new SupervisedUserInterstitial(web_contents, url, reason));
+    supervised_user_error_page::FilteringBehaviorReason reason,
+    int frame_id,
+    int64_t interstitial_navigation_id) {
+  std::unique_ptr<SupervisedUserInterstitial> interstitial =
+      base::WrapUnique(new SupervisedUserInterstitial(
+          web_contents, url, reason, frame_id, interstitial_navigation_id));
 
-  CleanUpInfoBar(web_contents);
+  if (web_contents->GetMainFrame()->GetFrameTreeNodeId() == frame_id)
+    CleanUpInfoBar(web_contents);
 
   // Caller is responsible for deleting the interstitial.
   return interstitial;
@@ -152,11 +165,15 @@
 SupervisedUserInterstitial::SupervisedUserInterstitial(
     WebContents* web_contents,
     const GURL& url,
-    supervised_user_error_page::FilteringBehaviorReason reason)
+    supervised_user_error_page::FilteringBehaviorReason reason,
+    int frame_id,
+    int64_t interstitial_navigation_id)
     : web_contents_(web_contents),
       profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
       url_(url),
-      reason_(reason) {}
+      reason_(reason),
+      frame_id_(frame_id),
+      interstitial_navigation_id_(interstitial_navigation_id) {}
 
 SupervisedUserInterstitial::~SupervisedUserInterstitial() {}
 
@@ -193,9 +210,12 @@
 }
 
 void SupervisedUserInterstitial::GoBack() {
+  // GoBack only for main frame.
+  DCHECK_EQ(web_contents()->GetMainFrame()->GetFrameTreeNodeId(), frame_id());
+
   UMA_HISTOGRAM_ENUMERATION("ManagedMode.BlockingInterstitialCommand", BACK,
                             HISTOGRAM_BOUNDING_VALUE);
-  MoveAwayFromCurrentPage();
+  AttemptMoveAwayFromCurrentFrameURL();
   OnInterstitialDone();
 }
 
@@ -203,6 +223,16 @@
     base::OnceCallback<void(bool)> RequestCallback) {
   UMA_HISTOGRAM_ENUMERATION("ManagedMode.BlockingInterstitialCommand",
                             ACCESS_REQUEST, HISTOGRAM_BOUNDING_VALUE);
+
+  RequestPermissionSource source;
+  if (web_contents()->GetMainFrame()->GetFrameTreeNodeId() == frame_id())
+    source = RequestPermissionSource::MAIN_FRAME;
+  else
+    source = RequestPermissionSource::SUB_FRAME;
+
+  UMA_HISTOGRAM_ENUMERATION("ManagedUsers.RequestPermissionSource", source,
+                            RequestPermissionSource::HISTOGRAM_BOUNDING_VALUE);
+
   SupervisedUserService* supervised_user_service =
       SupervisedUserServiceFactory::GetForProfile(profile_);
   supervised_user_service->AddURLAccessRequest(url_,
@@ -237,7 +267,7 @@
   return;
 }
 
-void SupervisedUserInterstitial::MoveAwayFromCurrentPage() {
+void SupervisedUserInterstitial::AttemptMoveAwayFromCurrentFrameURL() {
   // No need to do anything if the WebContents is in the process of being
   // destroyed anyway.
   if (web_contents_->IsBeingDestroyed())
@@ -260,5 +290,5 @@
   // After this, the WebContents may be destroyed. Make sure we don't try to use
   // it again.
   web_contents_ = nullptr;
-  navigation_observer->OnInterstitialDone();
+  navigation_observer->OnInterstitialDone(frame_id_);
 }
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.h b/chrome/browser/supervised_user/supervised_user_interstitial.h
index d0f92ca9..18e80f3 100644
--- a/chrome/browser/supervised_user/supervised_user_interstitial.h
+++ b/chrome/browser/supervised_user/supervised_user_interstitial.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_INTERSTITIAL_H_
 #define CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_INTERSTITIAL_H_
 
+#include <memory>
 #include <string>
 
 #include "base/callback_forward.h"
@@ -14,7 +15,7 @@
 
 namespace content {
 class WebContents;
-}
+}  // namespace content
 
 class Profile;
 
@@ -30,7 +31,9 @@
   static std::unique_ptr<SupervisedUserInterstitial> Create(
       content::WebContents* web_contents,
       const GURL& url,
-      supervised_user_error_page::FilteringBehaviorReason reason);
+      supervised_user_error_page::FilteringBehaviorReason reason,
+      int frame_id,
+      int64_t interstitial_navigation_id);
 
   static std::string GetHTMLContents(
       Profile* profile,
@@ -40,26 +43,42 @@
   void RequestPermission(base::OnceCallback<void(bool)> callback);
   void ShowFeedback();
 
+  // Getter methods.
+  content::WebContents* web_contents() { return web_contents_; }
+  int frame_id() const { return frame_id_; }
+  int64_t interstitial_navigation_id() const {
+    return interstitial_navigation_id_;
+  }
+  const GURL& url() const { return url_; }
+
  private:
   SupervisedUserInterstitial(
       content::WebContents* web_contents,
       const GURL& url,
-      supervised_user_error_page::FilteringBehaviorReason reason);
+      supervised_user_error_page::FilteringBehaviorReason reason,
+      int frame_id,
+      int64_t interstitial_navigation_id);
 
-  // Moves away from the page behind the interstitial when not proceeding with
-  // the request.
-  void MoveAwayFromCurrentPage();
+  // Tries to go back.
+  void AttemptMoveAwayFromCurrentFrameURL();
 
   void OnInterstitialDone();
 
-  // Owns the interstitial, which owns us.
+  // Owns SupervisedUserNavigationObserver which owns us.
   content::WebContents* web_contents_;
 
   Profile* profile_;
 
+  // The last committed url for this frame.
   GURL url_;
   supervised_user_error_page::FilteringBehaviorReason reason_;
 
+  // The uniquely identifying global id for the frame.
+  int frame_id_;
+
+  // The Navigation ID of the navigation that last triggered the interstitial.
+  int64_t interstitial_navigation_id_;
+
   DISALLOW_COPY_AND_ASSIGN(SupervisedUserInterstitial);
 };
 
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_observer.cc b/chrome/browser/supervised_user/supervised_user_navigation_observer.cc
index ad665620..e0e3605 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_observer.cc
+++ b/chrome/browser/supervised_user/supervised_user_navigation_observer.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/browser/supervised_user/supervised_user_navigation_observer.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/metrics/histogram_macros.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/supervised_user/supervised_user_interstitial.h"
@@ -21,6 +24,17 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/reload_type.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace {
+
+bool IsMainFrame(content::RenderFrameHost* render_frame_host) {
+  return !render_frame_host->GetParent();
+}
+
+}  // namespace
 
 using content::NavigationEntry;
 
@@ -45,6 +59,7 @@
     const GURL& url,
     supervised_user_error_page::FilteringBehaviorReason reason,
     int64_t navigation_id,
+    int frame_id,
     const base::Callback<
         void(SupervisedUserNavigationThrottle::CallbackActions)>& callback) {
   SupervisedUserNavigationObserver* navigation_observer =
@@ -58,7 +73,7 @@
   }
 
   navigation_observer->OnRequestBlockedInternal(url, reason, navigation_id,
-                                                callback);
+                                                frame_id, callback);
 }
 
 void SupervisedUserNavigationObserver::UpdateMainFrameFilteringStatus(
@@ -70,37 +85,95 @@
 
 void SupervisedUserNavigationObserver::DidFinishNavigation(
       content::NavigationHandle* navigation_handle) {
+  int frame_id = navigation_handle->GetFrameTreeNodeId();
+  int64_t navigation_id = navigation_handle->GetNavigationId();
+
   // If this is a different navigation than the one that triggered the
-  // interstitial, remove the interstitial.
-  if (interstitial_ &&
-      navigation_handle->GetNavigationId() != interstitial_navigation_id_) {
-    OnInterstitialDone();
+  // interstitial in the frame, then interstitial is done.
+  if (base::Contains(supervised_user_interstitials_, frame_id) &&
+      navigation_id != supervised_user_interstitials_[frame_id]
+                           ->interstitial_navigation_id()) {
+    OnInterstitialDone(frame_id);
   }
 
   // Only filter same page navigations (eg. pushState/popState); others will
   // have been filtered by the NavigationThrottle.
   if (navigation_handle->IsSameDocument() &&
       navigation_handle->IsInMainFrame()) {
+    auto* render_frame_host = navigation_handle->GetRenderFrameHost();
+    int process_id = render_frame_host->GetProcess()->GetID();
+    int routing_id = render_frame_host->GetRoutingID();
+
     url_filter_->GetFilteringBehaviorForURLWithAsyncChecks(
         web_contents()->GetLastCommittedURL(),
         base::BindOnce(
             &SupervisedUserNavigationObserver::URLFilterCheckCallback,
-            weak_ptr_factory_.GetWeakPtr(), navigation_handle->GetURL()));
+            weak_ptr_factory_.GetWeakPtr(), navigation_handle->GetURL(),
+            process_id, routing_id));
+  }
+}
+
+void SupervisedUserNavigationObserver::FrameDeleted(
+    content::RenderFrameHost* render_frame_host) {
+  int frame_id = render_frame_host->GetFrameTreeNodeId();
+  supervised_user_interstitials_.erase(frame_id);
+}
+
+void SupervisedUserNavigationObserver::DidFinishLoad(
+    content::RenderFrameHost* render_frame_host,
+    const GURL& validated_url) {
+  if (IsMainFrame(render_frame_host)) {
+    bool main_frame_blocked =
+        base::Contains(supervised_user_interstitials_,
+                       render_frame_host->GetFrameTreeNodeId());
+    int count = supervised_user_interstitials_.size();
+    if (main_frame_blocked)
+      count = 0;
+
+    UMA_HISTOGRAM_COUNTS_1000("ManagedUsers.BlockedIframeCount", count);
+  }
+
+  if (base::Contains(supervised_user_interstitials_,
+                     render_frame_host->GetFrameTreeNodeId())) {
+    UMA_HISTOGRAM_COUNTS_1000("ManagedUsers.BlockedFrameDepth",
+                              render_frame_host->GetFrameDepth());
   }
 }
 
 void SupervisedUserNavigationObserver::OnURLFilterChanged() {
+  auto* main_frame = web_contents()->GetMainFrame();
+  int main_frame_process_id = main_frame->GetProcess()->GetID();
+  int routing_id = main_frame->GetRoutingID();
+
   url_filter_->GetFilteringBehaviorForURLWithAsyncChecks(
       web_contents()->GetLastCommittedURL(),
       base::BindOnce(&SupervisedUserNavigationObserver::URLFilterCheckCallback,
                      weak_ptr_factory_.GetWeakPtr(),
-                     web_contents()->GetLastCommittedURL()));
+                     web_contents()->GetLastCommittedURL(),
+                     main_frame_process_id, routing_id));
+
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+  SupervisedUserService* service =
+      SupervisedUserServiceFactory::GetForProfile(profile);
+  if (!service->IsSupervisedUserIframeFilterEnabled())
+    return;
+
+  // Iframe filtering has been enabled.
+  web_contents()->ForEachFrame(
+      base::BindRepeating(&SupervisedUserNavigationObserver::FilterRenderFrame,
+                          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SupervisedUserNavigationObserver::OnInterstitialDone(int frame_id) {
+  supervised_user_interstitials_.erase(frame_id);
 }
 
 void SupervisedUserNavigationObserver::OnRequestBlockedInternal(
     const GURL& url,
     supervised_user_error_page::FilteringBehaviorReason reason,
     int64_t navigation_id,
+    int frame_id,
     const base::Callback<
         void(SupervisedUserNavigationThrottle::CallbackActions)>& callback) {
   // TODO(bauerb): Use SaneTime when available.
@@ -137,25 +210,41 @@
 
   // Show the interstitial.
   const bool initial_page_load = true;
-  MaybeShowInterstitial(url, reason, initial_page_load, navigation_id,
+  MaybeShowInterstitial(url, reason, initial_page_load, navigation_id, frame_id,
                         callback);
 }
 
 void SupervisedUserNavigationObserver::URLFilterCheckCallback(
     const GURL& url,
+    int render_frame_process_id,
+    int render_frame_routing_id,
     SupervisedUserURLFilter::FilteringBehavior behavior,
     supervised_user_error_page::FilteringBehaviorReason reason,
     bool uncertain) {
-  // If the page has been changed in the meantime, we can exit.
-  if (url != web_contents()->GetLastCommittedURL())
+  auto* render_frame_host = content::RenderFrameHost::FromID(
+      render_frame_process_id, render_frame_routing_id);
+
+  if (!render_frame_host || !render_frame_host->IsRenderFrameLive())
     return;
 
-  bool is_showing_interstitial = interstitial_.get() != nullptr;
+  int frame_id = render_frame_host->GetFrameTreeNodeId();
+  bool is_showing_interstitial =
+      base::Contains(supervised_user_interstitials_, frame_id);
   bool should_show_interstitial =
       behavior == SupervisedUserURLFilter::FilteringBehavior::BLOCK;
 
-  if (is_showing_interstitial != should_show_interstitial)
-    web_contents()->GetController().Reload(content::ReloadType::NORMAL, false);
+  // If an interstitial is being shown where it shouldn't (for e.g. because a
+  // parent just approved a request) reloading will clear it. On the other hand,
+  // if an interstitial error page is not being shown but it should be shown,
+  // then reloading will trigger the navigation throttle to show the error page.
+  if (is_showing_interstitial != should_show_interstitial) {
+    if (IsMainFrame(render_frame_host)) {
+      web_contents()->GetController().Reload(content::ReloadType::NORMAL,
+                                             /* check_for_repost */ false);
+      return;
+    }
+    render_frame_host->Reload();
+  }
 }
 
 void SupervisedUserNavigationObserver::MaybeShowInterstitial(
@@ -163,33 +252,65 @@
     supervised_user_error_page::FilteringBehaviorReason reason,
     bool initial_page_load,
     int64_t navigation_id,
+    int frame_id,
     const base::Callback<
         void(SupervisedUserNavigationThrottle::CallbackActions)>& callback) {
-  interstitial_navigation_id_ = navigation_id;
-  interstitial_ =
-      SupervisedUserInterstitial::Create(web_contents(), url, reason);
+  std::unique_ptr<SupervisedUserInterstitial> interstitial =
+      SupervisedUserInterstitial::Create(web_contents(), url, reason, frame_id,
+                                         navigation_id);
+
+  supervised_user_interstitials_[frame_id] = std::move(interstitial);
+
   callback.Run(SupervisedUserNavigationThrottle::CallbackActions::
                    kCancelWithInterstitial);
 }
 
-void SupervisedUserNavigationObserver::OnInterstitialDone() {
-  interstitial_.reset();
+void SupervisedUserNavigationObserver::FilterRenderFrame(
+    content::RenderFrameHost* render_frame_host) {
+  // If the RenderFrameHost is not live return.
+  // If the RenderFrameHost belongs to the main frame, return. This is because
+  // the main frame is already filtered in
+  // |SupervisedUserNavigationObserver::OnURLFilterChanged|.
+  if (!render_frame_host->IsRenderFrameLive() || IsMainFrame(render_frame_host))
+    return;
+
+  const GURL& last_committed_url = render_frame_host->GetLastCommittedURL();
+
+  url_filter_->GetFilteringBehaviorForURLWithAsyncChecks(
+      web_contents()->GetLastCommittedURL(),
+      base::BindOnce(&SupervisedUserNavigationObserver::URLFilterCheckCallback,
+                     weak_ptr_factory_.GetWeakPtr(), last_committed_url,
+                     render_frame_host->GetProcess()->GetID(),
+                     render_frame_host->GetRoutingID()));
 }
 
 void SupervisedUserNavigationObserver::GoBack() {
-  if (interstitial_)
-    interstitial_->GoBack();
+  auto* render_frame_host = binding_.GetCurrentTargetFrame();
+  auto id = render_frame_host->GetFrameTreeNodeId();
+
+  // Request can come only from the main frame.
+  if (!IsMainFrame(render_frame_host))
+    return;
+
+  if (base::Contains(supervised_user_interstitials_, id))
+    supervised_user_interstitials_[id]->GoBack();
 }
 
 void SupervisedUserNavigationObserver::RequestPermission(
     RequestPermissionCallback callback) {
-  if (interstitial_)
-    interstitial_->RequestPermission(std::move(callback));
+  auto* render_frame_host = binding_.GetCurrentTargetFrame();
+  int id = render_frame_host->GetFrameTreeNodeId();
+
+  if (base::Contains(supervised_user_interstitials_, id))
+    supervised_user_interstitials_[id]->RequestPermission(std::move(callback));
 }
 
 void SupervisedUserNavigationObserver::Feedback() {
-  if (interstitial_)
-    interstitial_->ShowFeedback();
+  auto* render_frame_host = binding_.GetCurrentTargetFrame();
+  int id = render_frame_host->GetFrameTreeNodeId();
+
+  if (base::Contains(supervised_user_interstitials_, id))
+    supervised_user_interstitials_[id]->ShowFeedback();
 }
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(SupervisedUserNavigationObserver)
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_observer.h b/chrome/browser/supervised_user/supervised_user_navigation_observer.h
index 0b3513e..a207c69 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_observer.h
+++ b/chrome/browser/supervised_user/supervised_user_navigation_observer.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_NAVIGATION_OBSERVER_H_
 #define CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_NAVIGATION_OBSERVER_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
@@ -24,8 +25,9 @@
 
 namespace content {
 class NavigationHandle;
+class RenderFrameHost;
 class WebContents;
-}
+}  // namespace content
 
 class SupervisedUserNavigationObserver
     : public content::WebContentsUserData<SupervisedUserNavigationObserver>,
@@ -46,6 +48,7 @@
       const GURL& url,
       supervised_user_error_page::FilteringBehaviorReason reason,
       int64_t navigation_id,
+      int frame_id,
       const base::Callback<
           void(SupervisedUserNavigationThrottle::CallbackActions)>& callback);
 
@@ -63,16 +66,24 @@
     return main_frame_filtering_behavior_reason_;
   }
 
-  // WebContentsObserver implementation.
+  // WebContentsObserver:
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override;
+  void FrameDeleted(content::RenderFrameHost* render_frame_host) override;
+  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
+                     const GURL& validated_url) override;
 
-  // SupervisedUserServiceObserver implementation.
+  // SupervisedUserServiceObserver:
   void OnURLFilterChanged() override;
 
   // Called when interstitial error page is no longer being shown in the main
   // frame.
-  void OnInterstitialDone();
+  void OnInterstitialDone(int frame_id);
+
+  const std::map<int, std::unique_ptr<SupervisedUserInterstitial>>&
+  interstitials_for_test() {
+    return supervised_user_interstitials_;
+  }
 
  private:
   friend class content::WebContentsUserData<SupervisedUserNavigationObserver>;
@@ -83,11 +94,14 @@
       const GURL& url,
       supervised_user_error_page::FilteringBehaviorReason reason,
       int64_t navigation_id,
+      int frame_id,
       const base::Callback<
           void(SupervisedUserNavigationThrottle::CallbackActions)>& callback);
 
   void URLFilterCheckCallback(
       const GURL& url,
+      int render_frame_process_id,
+      int render_frame_routing_id,
       SupervisedUserURLFilter::FilteringBehavior behavior,
       supervised_user_error_page::FilteringBehaviorReason reason,
       bool uncertain);
@@ -97,9 +111,13 @@
       supervised_user_error_page::FilteringBehaviorReason reason,
       bool initial_page_load,
       int64_t navigation_id,
+      int frame_id,
       const base::Callback<
           void(SupervisedUserNavigationThrottle::CallbackActions)>& callback);
 
+  // Filters the render frame host if render frame is live.
+  void FilterRenderFrame(content::RenderFrameHost* render_frame_host);
+
   // supervised_user::mojom::SupervisedUserCommands implementation. Should not
   // be called when an interstitial is no longer showing. This should be
   // enforced by the mojo caller.
@@ -113,8 +131,10 @@
   // Owned by SupervisedUserServiceFactory (lifetime of Profile).
   SupervisedUserService* supervised_user_service_;
 
-  // Navigation ID of the navigation that triggered the last interstitial.
-  int64_t interstitial_navigation_id_ = -1;
+  // Keeps track of the blocked frames. It maps the frame's globally unique
+  // id to its corresponding |SupervisedUserInterstitial| instance.
+  std::map<int, std::unique_ptr<SupervisedUserInterstitial>>
+      supervised_user_interstitials_;
 
   SupervisedUserURLFilter::FilteringBehavior main_frame_filtering_behavior_ =
       SupervisedUserURLFilter::FilteringBehavior::ALLOW;
@@ -125,8 +145,6 @@
   std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>>
       blocked_navigations_;
 
-  std::unique_ptr<SupervisedUserInterstitial> interstitial_;
-
   content::WebContentsFrameBindingSet<
       supervised_user::mojom::SupervisedUserCommands>
       binding_;
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc b/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc
index 5b4a62f..f827593 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc
+++ b/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc
@@ -126,8 +126,10 @@
       behavior == SupervisedUserURLFilter::FilteringBehavior::ALLOW;
   bool is_whitelisted =
       reason == supervised_user_error_page::FilteringBehaviorReason::WHITELIST;
+  bool is_manual =
+      reason == supervised_user_error_page::FilteringBehaviorReason::MANUAL;
 
-  return is_allowed && is_whitelisted;
+  return is_allowed && (is_whitelisted || is_manual);
 }
 
 }  // namespace
@@ -212,6 +214,7 @@
   SupervisedUserNavigationObserver::OnRequestBlocked(
       navigation_handle()->GetWebContents(), navigation_handle()->GetURL(),
       reason, navigation_handle()->GetNavigationId(),
+      navigation_handle()->GetFrameTreeNodeId(),
       base::Bind(&SupervisedUserNavigationThrottle::OnInterstitialResult,
                  weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc b/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
index be1b69ef0..0e41d61 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
+++ b/chrome/browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc
@@ -7,11 +7,18 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/supervised_user/logged_in_user_mixin.h"
+#include "chrome/browser/supervised_user/permission_request_creator_mock.h"
 #include "chrome/browser/supervised_user/supervised_user_constants.h"
+#include "chrome/browser/supervised_user/supervised_user_features.h"
+#include "chrome/browser/supervised_user/supervised_user_interstitial.h"
+#include "chrome/browser/supervised_user/supervised_user_navigation_observer.h"
+#include "chrome/browser/supervised_user/supervised_user_service.h"
+#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_settings_service.h"
 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_url_filter.h"
@@ -19,6 +26,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/page_type.h"
@@ -34,9 +42,85 @@
 
 static const char* kExampleHost = "www.example.com";
 static const char* kExampleHost2 = "www.example2.com";
-
+static const char* kIframeHost1 = "www.iframe1.com";
 static const char* kIframeHost2 = "www.iframe2.com";
 
+// Helper class to wait for a particular navigation in a particular render
+// frame.
+class NavigationFinishedWaiter : public content::WebContentsObserver {
+ public:
+  NavigationFinishedWaiter(WebContents* web_contents,
+                           int frame_id,
+                           const GURL& url)
+      : content::WebContentsObserver(web_contents),
+        frame_id_(frame_id),
+        url_(url) {}
+
+  ~NavigationFinishedWaiter() override = default;
+
+  void Wait() {
+    if (did_finish_)
+      return;
+    run_loop_.Run();
+  }
+
+  // content::WebContentsObserver:
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
+
+ private:
+  int frame_id_;
+  GURL url_;
+  bool did_finish_ = false;
+  base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed};
+
+  DISALLOW_COPY_AND_ASSIGN(NavigationFinishedWaiter);
+};
+
+void NavigationFinishedWaiter::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (navigation_handle->GetFrameTreeNodeId() != frame_id_ ||
+      navigation_handle->GetURL() != url_)
+    return;
+  did_finish_ = true;
+  run_loop_.Quit();
+}
+
+// Class to keep track of iframes created and destroyed.
+class RenderFrameTracker : public content::WebContentsObserver {
+ public:
+  explicit RenderFrameTracker(content::WebContents* web_contents)
+      : content::WebContentsObserver(web_contents) {}
+  ~RenderFrameTracker() override = default;
+
+  // content::WebContentsObserver:
+  void RenderFrameHostChanged(content::RenderFrameHost* old_host,
+                              content::RenderFrameHost* new_host) override;
+  void FrameDeleted(content::RenderFrameHost* host) override;
+
+  content::RenderFrameHost* GetHost(int frame_id) {
+    if (!base::Contains(render_frame_hosts_, frame_id))
+      return nullptr;
+    return render_frame_hosts_[frame_id];
+  }
+
+ private:
+  std::map<int, content::RenderFrameHost*> render_frame_hosts_;
+};
+
+void RenderFrameTracker::RenderFrameHostChanged(
+    content::RenderFrameHost* old_host,
+    content::RenderFrameHost* new_host) {
+  render_frame_hosts_[new_host->GetFrameTreeNodeId()] = new_host;
+}
+
+void RenderFrameTracker::FrameDeleted(content::RenderFrameHost* host) {
+  if (!base::Contains(render_frame_hosts_, host->GetFrameTreeNodeId()))
+    return;
+
+  render_frame_hosts_.erase(host->GetFrameTreeNodeId());
+}
+
 }  // namespace
 
 class SupervisedUserNavigationThrottleTest
@@ -45,6 +129,9 @@
   SupervisedUserNavigationThrottleTest() = default;
   ~SupervisedUserNavigationThrottleTest() override = default;
 
+  void SetUp() override;
+  void SetUpOnMainThread() override;
+
   void BlockHost(const std::string& host) {
     Profile* profile = browser()->profile();
     SupervisedUserSettingsService* settings_service =
@@ -83,9 +170,6 @@
   }
 
  private:
-  void SetUp() override;
-  void SetUpOnMainThread() override;
-
   std::unique_ptr<chromeos::LoggedInUserMixin> logged_in_user_mixin_;
 };
 
@@ -179,6 +263,205 @@
   EXPECT_TRUE(loaded2);
 }
 
+class SupervisedUserIframeFilterTest
+    : public SupervisedUserNavigationThrottleTest {
+ protected:
+  SupervisedUserIframeFilterTest() = default;
+  ~SupervisedUserIframeFilterTest() override = default;
+
+  void SetUp() override;
+  void SetUpOnMainThread() override;
+  void TearDownOnMainThread() override;
+
+  std::vector<int> GetBlockedFrames();
+  const GURL& GetBlockedFrameURL(int frame_id);
+  bool IsInterstitialBeingShownInFrame(int frame_id);
+  void RequestPermissionFromFrame(int frame_id);
+  void WaitForNavigationFinished(int frame_id, const GURL& url);
+
+  PermissionRequestCreatorMock* permission_creator() {
+    return permission_creator_;
+  }
+
+  RenderFrameTracker* tracker() { return tracker_.get(); }
+
+ private:
+  std::unique_ptr<RenderFrameTracker> tracker_;
+  PermissionRequestCreatorMock* permission_creator_;
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+void SupervisedUserIframeFilterTest::SetUp() {
+  scoped_feature_list_.InitAndEnableFeature(
+      supervised_users::kSupervisedUserIframeFilter);
+  SupervisedUserNavigationThrottleTest::SetUp();
+}
+
+void SupervisedUserIframeFilterTest::SetUpOnMainThread() {
+  SupervisedUserNavigationThrottleTest::SetUpOnMainThread();
+
+  SupervisedUserService* service =
+      SupervisedUserServiceFactory::GetForProfile(browser()->profile());
+  std::unique_ptr<PermissionRequestCreator> creator =
+      std::make_unique<PermissionRequestCreatorMock>(browser()->profile());
+  permission_creator_ =
+      static_cast<PermissionRequestCreatorMock*>(creator.get());
+  permission_creator_->SetEnabled();
+  service->SetPrimaryPermissionCreatorForTest(std::move(creator));
+
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  tracker_ = std::make_unique<RenderFrameTracker>(tab);
+}
+
+void SupervisedUserIframeFilterTest::TearDownOnMainThread() {
+  tracker_.reset();
+  SupervisedUserNavigationThrottleTest::TearDownOnMainThread();
+}
+
+std::vector<int> SupervisedUserIframeFilterTest::GetBlockedFrames() {
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* navigation_observer =
+      SupervisedUserNavigationObserver::FromWebContents(tab);
+  const auto& interstitials = navigation_observer->interstitials_for_test();
+
+  std::vector<int> blocked_frames;
+  blocked_frames.reserve(interstitials.size());
+
+  for (const auto& elem : interstitials)
+    blocked_frames.push_back(elem.first);
+
+  return blocked_frames;
+}
+
+const GURL& SupervisedUserIframeFilterTest::GetBlockedFrameURL(int frame_id) {
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* navigation_observer =
+      SupervisedUserNavigationObserver::FromWebContents(tab);
+  const auto& interstitials = navigation_observer->interstitials_for_test();
+  DCHECK(base::Contains(interstitials, frame_id));
+  return interstitials.at(frame_id)->url();
+}
+
+bool SupervisedUserIframeFilterTest::IsInterstitialBeingShownInFrame(
+    int frame_id) {
+  // First check that SupervisedUserNavigationObserver believes that there is
+  // an error page in the frame hosted by |rfh|.
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* navigation_observer =
+      SupervisedUserNavigationObserver::FromWebContents(tab);
+  auto& interstitials = navigation_observer->interstitials_for_test();
+
+  if (!base::Contains(interstitials, frame_id))
+    return false;
+
+  // Then check that an error page has actually been loaded in the frame.
+  std::string command =
+      "domAutomationController.send("
+      "(document.getElementsByClassName('supervised-user-block') != null) "
+      "? (true) : (false));";
+
+  auto* render_frame_host = tracker()->GetHost(frame_id);
+  DCHECK(render_frame_host->IsRenderFrameLive());
+
+  bool value = false;
+  auto target = content::ToRenderFrameHost(render_frame_host);
+  EXPECT_TRUE(content::ExecuteScriptWithoutUserGestureAndExtractBool(
+      target, command, &value));
+  return value;
+}
+
+void SupervisedUserIframeFilterTest::RequestPermissionFromFrame(int frame_id) {
+  auto* render_frame_host = tracker()->GetHost(frame_id);
+  DCHECK(render_frame_host);
+  DCHECK(render_frame_host->IsRenderFrameLive());
+  std::string command = "sendCommand(\'request\')";
+  ASSERT_TRUE(content::ExecuteScript(
+      content::ToRenderFrameHost(render_frame_host), command));
+}
+
+void SupervisedUserIframeFilterTest::WaitForNavigationFinished(
+    int frame_id,
+    const GURL& url) {
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  NavigationFinishedWaiter waiter(tab, frame_id, url);
+  waiter.Wait();
+}
+
+IN_PROC_BROWSER_TEST_F(SupervisedUserIframeFilterTest, BlockSubFrame) {
+  BlockHost(kIframeHost2);
+  GURL allowed_url_with_iframes = embedded_test_server()->GetURL(
+      kExampleHost, "/supervised_user/with_iframes.html");
+  ui_test_utils::NavigateToURL(browser(), allowed_url_with_iframes);
+  EXPECT_FALSE(IsInterstitialBeingShown(browser()));
+
+  // The first iframe's source is |kIframeHost1| and it is not blocked. It will
+  // successfully load.
+  auto blocked = GetBlockedFrames();
+  EXPECT_EQ(blocked.size(), 1u);
+
+  int blocked_frame_id = blocked[0];
+
+  EXPECT_TRUE(IsInterstitialBeingShownInFrame(blocked_frame_id));
+
+  permission_creator()->SetPermissionResult(true);
+  RequestPermissionFromFrame(blocked_frame_id);
+  EXPECT_EQ(permission_creator()->url_requests().size(), 1u);
+  std::string requested_host = permission_creator()->url_requests()[0].host();
+
+  EXPECT_EQ(requested_host, kIframeHost2);
+
+  WaitForNavigationFinished(blocked[0],
+                            permission_creator()->url_requests()[0]);
+
+  EXPECT_FALSE(IsInterstitialBeingShownInFrame(blocked_frame_id));
+}
+
+IN_PROC_BROWSER_TEST_F(SupervisedUserIframeFilterTest, BlockMultipleSubFrames) {
+  BlockHost(kIframeHost1);
+  BlockHost(kIframeHost2);
+
+  GURL allowed_url_with_iframes = embedded_test_server()->GetURL(
+      kExampleHost, "/supervised_user/with_iframes.html");
+  ui_test_utils::NavigateToURL(browser(), allowed_url_with_iframes);
+  EXPECT_FALSE(IsInterstitialBeingShown(browser()));
+
+  auto blocked = GetBlockedFrames();
+  EXPECT_EQ(blocked.size(), 2u);
+
+  int blocked_frame_id_1 = blocked[0];
+  GURL blocked_frame_url_1 = GetBlockedFrameURL(blocked_frame_id_1);
+
+  int blocked_frame_id_2 = blocked[1];
+  GURL blocked_frame_url_2 = GetBlockedFrameURL(blocked_frame_id_2);
+
+  EXPECT_TRUE(IsInterstitialBeingShownInFrame(blocked_frame_id_1));
+
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+
+  permission_creator()->SetPermissionResult(true);
+  permission_creator()->DelayHandlingForNextRequests();
+
+  RequestPermissionFromFrame(blocked_frame_id_1);
+  RequestPermissionFromFrame(blocked_frame_id_2);
+
+  EXPECT_EQ(permission_creator()->url_requests().size(), 2u);
+  EXPECT_EQ(permission_creator()->url_requests()[0], GURL(blocked_frame_url_1));
+  EXPECT_EQ(permission_creator()->url_requests()[1], GURL(blocked_frame_url_2));
+
+  NavigationFinishedWaiter waiter1(tab, blocked_frame_id_1,
+                                   blocked_frame_url_1);
+  NavigationFinishedWaiter waiter2(tab, blocked_frame_id_2,
+                                   blocked_frame_url_2);
+
+  permission_creator()->HandleDelayedRequests();
+
+  waiter1.Wait();
+  waiter2.Wait();
+
+  DCHECK_EQ(GetBlockedFrames().size(), 0u);
+}
+
 class SupervisedUserNavigationThrottleNotSupervisedTest
     : public SupervisedUserNavigationThrottleTest {
  protected:
diff --git a/chrome/browser/supervised_user/supervised_user_service.cc b/chrome/browser/supervised_user/supervised_user_service.cc
index bdcf244..8ba00e3 100644
--- a/chrome/browser/supervised_user/supervised_user_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_service.cc
@@ -64,7 +64,6 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #endif
 
@@ -285,12 +284,7 @@
       is_profile_active_(false),
       did_init_(false),
       did_shutdown_(false),
-      blacklist_state_(BlacklistLoadState::NOT_LOADED)
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-      ,
-      registry_observer_(this)
-#endif
-{
+      blacklist_state_(BlacklistLoadState::NOT_LOADED) {
   url_filter_.AddObserver(this);
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   registry_observer_.Add(extensions::ExtensionRegistry::Get(profile));
@@ -303,6 +297,18 @@
       g_browser_process->supervised_user_whitelist_installer(), client_id);
 }
 
+void SupervisedUserService::SetPrimaryPermissionCreatorForTest(
+    std::unique_ptr<PermissionRequestCreator> permission_creator) {
+  if (permissions_creators_.empty()) {
+    permissions_creators_.push_back(std::move(permission_creator));
+    return;
+  }
+
+  // Else there are other permission creators.
+  permissions_creators_.insert(permissions_creators_.begin(),
+                               std::move(permission_creator));
+}
+
 void SupervisedUserService::SetActive(bool active) {
   if (active_ == active)
     return;
diff --git a/chrome/browser/supervised_user/supervised_user_service.h b/chrome/browser/supervised_user/supervised_user_service.h
index a184057..b1c931f3 100644
--- a/chrome/browser/supervised_user/supervised_user_service.h
+++ b/chrome/browser/supervised_user/supervised_user_service.h
@@ -30,6 +30,7 @@
 #include "extensions/buildflags/buildflags.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
 #include "extensions/browser/management_policy.h"
 #endif
@@ -48,10 +49,6 @@
 class Version;
 }
 
-namespace extensions {
-class ExtensionRegistry;
-}
-
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
@@ -177,6 +174,9 @@
   }
 #endif  // !defined(OS_ANDROID)
 
+  void SetPrimaryPermissionCreatorForTest(
+      std::unique_ptr<PermissionRequestCreator> permission_creator);
+
  private:
   friend class SupervisedUserServiceExtensionTestBase;
   friend class SupervisedUserServiceFactory;
@@ -339,7 +339,7 @@
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   ScopedObserver<extensions::ExtensionRegistry,
                  extensions::ExtensionRegistryObserver>
-      registry_observer_;
+      registry_observer_{this};
 #endif
 
   base::ObserverList<SupervisedUserServiceObserver>::Unchecked observer_list_;
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.cc b/chrome/browser/supervised_user/supervised_user_url_filter.cc
index cc80a45..3929ccc8 100644
--- a/chrome/browser/supervised_user/supervised_user_url_filter.cc
+++ b/chrome/browser/supervised_user/supervised_user_url_filter.cc
@@ -599,11 +599,11 @@
   async_url_checker_.reset();
 }
 
-void SupervisedUserURLFilter::AddObserver(Observer* observer) const {
+void SupervisedUserURLFilter::AddObserver(Observer* observer) {
   observers_.AddObserver(observer);
 }
 
-void SupervisedUserURLFilter::RemoveObserver(Observer* observer) const {
+void SupervisedUserURLFilter::RemoveObserver(Observer* observer) {
   observers_.RemoveObserver(observer);
 }
 
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.h b/chrome/browser/supervised_user/supervised_user_url_filter.h
index b041b707..82317a9e 100644
--- a/chrome/browser/supervised_user/supervised_user_url_filter.h
+++ b/chrome/browser/supervised_user/supervised_user_url_filter.h
@@ -164,8 +164,8 @@
   // present, and resets the default behavior to "allow".
   void Clear();
 
-  void AddObserver(Observer* observer) const;
-  void RemoveObserver(Observer* observer) const;
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
 
   // Sets a different task runner for testing.
   void SetBlockingTaskRunnerForTesting(
@@ -187,8 +187,7 @@
                      safe_search_api::Classification classification,
                      bool uncertain) const;
 
-  // This is mutable to allow notification in const member functions.
-  mutable base::ObserverList<Observer>::Unchecked observers_;
+  base::ObserverList<Observer>::Unchecked observers_;
 
   FilteringBehavior default_behavior_;
   std::unique_ptr<Contents> contents_;
diff --git a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
index de00e72..6044fcf 100644
--- a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
@@ -787,6 +787,14 @@
                                          /*REMOTE_INITIAL_UPDATE=*/5));
 }
 
+// TODO(crbug.com/1012222): re-enable this test on all builders once flakiness
+// is addressed.
+#if defined(THREAD_SANITIZER)
+#define MAYBE_ApplyRemoteCreationWithValidGUID \
+  DISABLED_ApplyRemoteCreationWithValidGUID
+#else
+#define MAYBE_ApplyRemoteCreationWithValidGUID ApplyRemoteCreationWithValidGUID
+#endif
 IN_PROC_BROWSER_TEST_P(SingleClientBookmarksSyncTest,
                        ApplyRemoteCreationWithValidGUID) {
   // This test is only relevant for USS code path.
@@ -991,8 +999,16 @@
                                             originator_client_item_id));
 }
 
+// TODO(crbug.com/1012223): re-enable this test on all builders once flakiness
+// is addressed.
+#if defined(THREAD_SANITIZER)
+#define MAYBE_ApplyRemoteUpdateWithValidGUID \
+  DISABLED_ApplyRemoteUpdateWithValidGUID
+#else
+#define MAYBE_ApplyRemoteUpdateWithValidGUID ApplyRemoteUpdateWithValidGUID
+#endif
 IN_PROC_BROWSER_TEST_P(SingleClientBookmarksSyncTest,
-                       ApplyRemoteUpdateWithValidGUID) {
+                       MAYBE_ApplyRemoteUpdateWithValidGUID) {
   // This test is only relevant for USS code path and when BookmarkNode GUID
   // replacement is enabled.
   if (!base::FeatureList::IsEnabled(switches::kSyncUSSBookmarks))
diff --git a/chrome/browser/translate/translate_fake_page.cc b/chrome/browser/translate/translate_fake_page.cc
index c2c4d0c..d62286a 100644
--- a/chrome/browser/translate/translate_fake_page.cc
+++ b/chrome/browser/translate/translate_fake_page.cc
@@ -48,8 +48,6 @@
 
 // translate::mojom::Page implementation.
 void FakePageImpl::Translate(const std::string& translate_script,
-                             network::mojom::URLLoaderFactoryPtr
-                                 unused_loader_factory_for_translate_script,
                              const std::string& source_lang,
                              const std::string& target_lang,
                              TranslateCallback callback) {
diff --git a/chrome/browser/translate/translate_fake_page.h b/chrome/browser/translate/translate_fake_page.h
index 668c7068..f2a0ada 100644
--- a/chrome/browser/translate/translate_fake_page.h
+++ b/chrome/browser/translate/translate_fake_page.h
@@ -48,12 +48,10 @@
   mojo::PendingRemote<translate::mojom::Page> BindToNewPageRemote();
 
   // translate::mojom::Page implementation.
-  void Translate(
-      const std::string& translate_script,
-      network::mojom::URLLoaderFactoryPtr loader_factory_for_translate_script,
-      const std::string& source_lang,
-      const std::string& target_lang,
-      TranslateCallback callback) override;
+  void Translate(const std::string& translate_script,
+                 const std::string& source_lang,
+                 const std::string& target_lang,
+                 TranslateCallback callback) override;
 
   void RevertTranslation() override;
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 248901130..4d01ecf 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -45,6 +45,7 @@
     "app_list/app_list_util.h",
 
     # All other browser/ui/app_list files go under enable_app_list below.
+    "autofill/autofill_bubble_handler.h",
     "autofill/autofill_popup_controller.h",
     "autofill/autofill_popup_controller_impl.cc",
     "autofill/autofill_popup_controller_impl.h",
@@ -70,6 +71,8 @@
     "autofill/popup_controller_common.h",
     "autofill/popup_view_common.cc",
     "autofill/popup_view_common.h",
+    "autofill/test/test_autofill_bubble_handler.cc",
+    "autofill/test/test_autofill_bubble_handler.h",
     "blocked_content/blocked_window_params.cc",
     "blocked_content/blocked_window_params.h",
     "blocked_content/list_item_position.cc",
@@ -2603,6 +2606,8 @@
       "views/apps/app_info_dialog/app_info_summary_panel.h",
       "views/apps/chrome_native_app_window_views.cc",
       "views/apps/chrome_native_app_window_views.h",
+      "views/autofill/autofill_bubble_handler_impl.cc",
+      "views/autofill/autofill_bubble_handler_impl.h",
       "views/autofill/autofill_popup_base_view.cc",
       "views/autofill/autofill_popup_base_view.h",
       "views/autofill/autofill_popup_view_native_views.cc",
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.h b/chrome/browser/ui/app_list/app_list_client_impl.h
index fc57c600..7a6504c 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl.h
+++ b/chrome/browser/ui/app_list/app_list_client_impl.h
@@ -178,7 +178,7 @@
   std::unique_ptr<app_list::SearchController> search_controller_;
   std::unique_ptr<AppSyncUIStateWatcher> app_sync_ui_state_watcher_;
 
-  ScopedObserver<TemplateURLService, AppListClientImpl>
+  ScopedObserver<TemplateURLService, TemplateURLServiceObserver>
       template_url_service_observer_{this};
 
   ash::AppListController* app_list_controller_ = nullptr;
diff --git a/chrome/browser/ui/app_list/arc/arc_app_test.cc b/chrome/browser/ui/app_list/arc/arc_app_test.cc
index 1efec68..6038261f5 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_test.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_test.cc
@@ -122,15 +122,16 @@
       arc::SetArcPlayStoreEnabledForProfile(profile_, true);
     if (!arc::IsArcPlayStoreEnabledPreferenceManagedForProfile(profile_))
       EXPECT_TRUE(arc_session_manager_->enable_requested());
-  }
 
-  app_instance_ = std::make_unique<arc::FakeAppInstance>(arc_app_list_pref_);
-  arc_service_manager_->arc_bridge_service()->app()->SetInstance(
-      app_instance_.get());
-  // TODO(khmel): Resolve this gracefully. Set of default app tests does not
-  // expect waiting in ArcAppTest setup.
-  if (wait_default_apps_)
-    WaitForInstanceReady(arc_service_manager_->arc_bridge_service()->app());
+    app_instance_ = std::make_unique<arc::FakeAppInstance>(arc_app_list_pref_);
+    arc_service_manager_->arc_bridge_service()->app()->SetInstance(
+        app_instance_.get());
+
+    // TODO(khmel): Resolve this gracefully. Set of default app tests does not
+    // expect waiting in ArcAppTest setup.
+    if (wait_default_apps_)
+      WaitForInstanceReady(arc_service_manager_->arc_bridge_service()->app());
+  }
 
   // Ensure that the singleton apps::ArcApps is constructed.
   if (base::FeatureList::IsEnabled(features::kAppServiceAsh))
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
index 996b6f3..961b7839 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -252,6 +252,8 @@
 const char kPlayStoreActivity[] = "com.android.vending.AssetBrowserActivity";
 const char kSettingsAppId[] = "mconboelelhjpkbdhhiijkgcimoangdj";
 const char kInitialStartParam[] = "S.org.chromium.arc.start_type=initialStart";
+const char kRequestStartTimeParamTemplate[] =
+    "S.org.chromium.arc.request.start=%ld";
 constexpr char kSettingsAppPackage[] = "com.android.settings";
 const char kSettingsAppDomainUrlActivity[] =
     "com.android.settings.Settings$ManageDomainUrlsActivity";
@@ -335,6 +337,7 @@
 
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context);
   std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(app_id);
+  base::Optional<std::string> launch_intent_to_send = std::move(launch_intent);
   if (app_info && !app_info->ready) {
     if (!IsArcPlayStoreEnabledForProfile(profile)) {
       if (prefs->IsDefault(app_id)) {
@@ -379,8 +382,9 @@
     // chrome_controller may be null in tests.
     if (chrome_controller) {
       chrome_controller->GetShelfSpinnerController()->AddSpinnerToShelf(
-          app_id, std::make_unique<ArcShelfSpinnerItemController>(
-                      app_id, event_flags, GetValidDisplayId(display_id)));
+          app_id,
+          std::make_unique<ArcShelfSpinnerItemController>(
+              app_id, event_flags, user_action, GetValidDisplayId(display_id)));
 
       // On some boards, ARC is booted with a restricted set of resources by
       // default to avoid slowing down Chrome's user session restoration.
@@ -390,10 +394,18 @@
     }
     prefs->SetLastLaunchTime(app_id);
     return true;
+  } else if (app_id == kPlayStoreAppId && !launch_intent_to_send) {
+    // Record launch request time in order to track Play Store default launch
+    // performance.
+    launch_intent_to_send = GetLaunchIntent(
+        kPlayStorePackage, kPlayStoreActivity,
+        {base::StringPrintf(
+            kRequestStartTimeParamTemplate,
+            (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds())});
   }
 
   arc::ArcBootPhaseMonitorBridge::RecordFirstAppLaunchDelayUMA(context);
-  return Launch(context, app_id, launch_intent, event_flags,
+  return Launch(context, app_id, launch_intent_to_send, event_flags,
                 GetValidDisplayId(display_id));
 }
 
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.h b/chrome/browser/ui/app_list/arc/arc_app_utils.h
index 88b1662e..2143054 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.h
@@ -40,6 +40,7 @@
 extern const char kPlayStoreActivity[];
 extern const char kSettingsAppId[];
 extern const char kInitialStartParam[];
+extern const char kRequestStartTimeParamTemplate[];
 extern const char kSettingsAppDomainUrlActivity[];
 
 // Represents unparsed intent.
diff --git a/chrome/browser/ui/app_list/search/app_service_app_result.cc b/chrome/browser/ui/app_list/search/app_service_app_result.cc
index 4ff1862..9d36e2c 100644
--- a/chrome/browser/ui/app_list/search/app_service_app_result.cc
+++ b/chrome/browser/ui/app_list/search/app_service_app_result.cc
@@ -7,6 +7,7 @@
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "base/bind.h"
+#include "chrome/browser/apps/app_service/app_service_metrics.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
@@ -52,10 +53,7 @@
       // TODO(crbug.com/826982): Is this SetResultType call necessary?? Does
       // anyone care about the kInternalApp vs kInstalledApp distinction?
       SetResultType(ResultType::kInternalApp);
-      // TODO(crbug.com/826982): Move this from the App Service caller to
-      // callee, closer to where other histograms are updated in
-      // BuiltInChromeOsApps::Launch??
-      InternalAppResult::RecordShowHistogram(app_id);
+      apps::RecordBuiltInAppSearchResult(app_id);
       break;
     case apps::mojom::AppType::kExtension:
       // TODO(crbug.com/826982): why do we pass the URL and not the app_id??
diff --git a/chrome/browser/ui/app_list/search/zero_state_file_provider.cc b/chrome/browser/ui/app_list/search/zero_state_file_provider.cc
index 99b1d27b..8e91612 100644
--- a/chrome/browser/ui/app_list/search/zero_state_file_provider.cc
+++ b/chrome/browser/ui/app_list/search/zero_state_file_provider.cc
@@ -13,7 +13,6 @@
 #include "base/task/task_traits.h"
 #include "base/task_runner_util.h"
 #include "base/threading/scoped_blocking_call.h"
-#include "chrome/browser/chromeos/file_manager/file_tasks_notifier.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h"
@@ -49,7 +48,7 @@
 }  // namespace
 
 ZeroStateFileProvider::ZeroStateFileProvider(Profile* profile)
-    : profile_(profile), file_tasks_observer_(this), weak_factory_(this) {
+    : profile_(profile) {
   DCHECK(profile_);
   task_runner_ = base::CreateSequencedTaskRunner(
       {base::ThreadPool(), base::TaskPriority::BEST_EFFORT, base::MayBlock(),
@@ -80,7 +79,7 @@
 void ZeroStateFileProvider::Start(const base::string16& query) {
   query_start_time_ = base::TimeTicks::Now();
   ClearResultsSilently();
-  if (!query.empty())
+  if (!files_ranker_ || !query.empty())
     return;
 
   base::PostTaskAndReplyWithResult(
diff --git a/chrome/browser/ui/app_list/search/zero_state_file_provider.h b/chrome/browser/ui/app_list/search/zero_state_file_provider.h
index 71a2e6e1..76ad789 100644
--- a/chrome/browser/ui/app_list/search/zero_state_file_provider.h
+++ b/chrome/browser/ui/app_list/search/zero_state_file_provider.h
@@ -17,17 +17,12 @@
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/file_manager/file_tasks_notifier.h"
 #include "chrome/browser/chromeos/file_manager/file_tasks_observer.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
 
 class Profile;
 
-namespace file_manager {
-namespace file_tasks {
-class FileTasksNotifier;
-}
-}  // namespace file_manager
-
 namespace app_list {
 namespace internal {
 
@@ -69,12 +64,12 @@
 
   ScopedObserver<file_manager::file_tasks::FileTasksNotifier,
                  file_manager::file_tasks::FileTasksObserver>
-      file_tasks_observer_;
+      file_tasks_observer_{this};
 
   SEQUENCE_CHECKER(sequence_checker_);
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  base::WeakPtrFactory<ZeroStateFileProvider> weak_factory_;
+  base::WeakPtrFactory<ZeroStateFileProvider> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ZeroStateFileProvider);
 };
diff --git a/chrome/browser/ui/ash/assistant/assistant_image_downloader.cc b/chrome/browser/ui/ash/assistant/assistant_image_downloader.cc
index 96e4732..10b52e0 100644
--- a/chrome/browser/ui/ash/assistant/assistant_image_downloader.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_image_downloader.cc
@@ -62,7 +62,7 @@
     bitmap_fetcher_->Init(
         /*referrer=*/std::string(), net::URLRequest::NEVER_CLEAR_REFERRER,
         net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
-            net::LOAD_DO_NOT_SEND_AUTH_DATA | net::LOAD_MAYBE_USER_GESTURE);
+            net::LOAD_DO_NOT_SEND_AUTH_DATA);
 
     bitmap_fetcher_->Start(
         content::BrowserContext::GetDefaultStoragePartition(profile)
diff --git a/chrome/browser/ui/ash/assistant/device_actions.cc b/chrome/browser/ui/ash/assistant/device_actions.cc
index b5fe556..42afc3f 100644
--- a/chrome/browser/ui/ash/assistant/device_actions.cc
+++ b/chrome/browser/ui/ash/assistant/device_actions.cc
@@ -117,7 +117,7 @@
 
 }  // namespace
 
-DeviceActions::DeviceActions() : scoped_prefs_observer_(this) {}
+DeviceActions::DeviceActions() = default;
 
 DeviceActions::~DeviceActions() {
   receivers_.Clear();
diff --git a/chrome/browser/ui/ash/assistant/device_actions.h b/chrome/browser/ui/ash/assistant/device_actions.h
index cc89f95..91abd9b5 100644
--- a/chrome/browser/ui/ash/assistant/device_actions.h
+++ b/chrome/browser/ui/ash/assistant/device_actions.h
@@ -49,7 +49,8 @@
                        const ArcAppListPrefs::AppInfo& app_info) override;
   void OnAppRemoved(const std::string& id) override;
 
-  ScopedObserver<ArcAppListPrefs, DeviceActions> scoped_prefs_observer_;
+  ScopedObserver<ArcAppListPrefs, ArcAppListPrefs::Observer>
+      scoped_prefs_observer_{this};
   mojo::ReceiverSet<chromeos::assistant::mojom::DeviceActions> receivers_;
   mojo::InterfacePtrSet<chromeos::assistant::mojom::AppListEventSubscriber>
       app_list_subscribers_;
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
index f54b772..6ba6fc2 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
@@ -13,13 +13,12 @@
 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
 #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/window.h"
 #include "ui/base/base_window.h"
 #include "ui/wm/core/window_util.h"
 
 AppWindowLauncherItemController::AppWindowLauncherItemController(
     const ash::ShelfID& shelf_id)
-    : ash::ShelfItemDelegate(shelf_id), observed_windows_(this) {}
+    : ash::ShelfItemDelegate(shelf_id) {}
 
 AppWindowLauncherItemController::~AppWindowLauncherItemController() {}
 
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
index 4723cbc9..f7fd962 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
@@ -12,12 +12,9 @@
 #include "ash/public/cpp/shelf_item_delegate.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 
-namespace aura {
-class Window;
-}
-
 namespace ui {
 class BaseWindow;
 }
@@ -105,7 +102,7 @@
   ui::BaseWindow* last_active_window_ = nullptr;
 
   // Scoped list of observed windows (for removal on destruction)
-  ScopedObserver<aura::Window, aura::WindowObserver> observed_windows_;
+  ScopedObserver<aura::Window, aura::WindowObserver> observed_windows_{this};
 
   std::unique_ptr<LauncherContextMenu> context_menu_;
 
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
index 26b668f9..8fa067b6 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -512,19 +512,8 @@
   app_window->SetController(controller);
   app_window->set_shelf_id(shelf_id);
 
-  if (!opt_in_management_check_start_time_.is_null() &&
-      app_window_info->app_shelf_id().app_id() == arc::kPlayStoreAppId) {
-    arc::Intent intent;
-    if (arc::ParseIntent(app_window_info->launch_intent(), &intent) &&
-        intent.HasExtraParam(arc::kInitialStartParam)) {
-      DCHECK(!arc::IsRobotOrOfflineDemoAccountMode());
-      arc::UpdatePlayStoreShowTime(
-          base::Time::Now() - opt_in_management_check_start_time_,
-          owner()->profile());
-      VLOG(1) << "Play Store is initially shown.";
-    }
-    opt_in_management_check_start_time_ = base::Time();
-  }
+  if (app_window_info->app_shelf_id().app_id() == arc::kPlayStoreAppId)
+    HandlePlayStoreLaunch(app_window_info);
 }
 
 void ArcAppWindowLauncherController::UnregisterApp(
@@ -539,3 +528,34 @@
   app_window->SetController(nullptr);
   app_window_info->set_app_window(nullptr);
 }
+
+void ArcAppWindowLauncherController::HandlePlayStoreLaunch(
+    AppWindowInfo* app_window_info) {
+  arc::Intent intent;
+  if (!arc::ParseIntent(app_window_info->launch_intent(), &intent))
+    return;
+
+  if (!opt_in_management_check_start_time_.is_null()) {
+    if (intent.HasExtraParam(arc::kInitialStartParam)) {
+      DCHECK(!arc::IsRobotOrOfflineDemoAccountMode());
+      arc::UpdatePlayStoreShownTimeDeprecated(
+          base::Time::Now() - opt_in_management_check_start_time_,
+          owner()->profile());
+      VLOG(1) << "Play Store is initially shown.";
+    }
+    opt_in_management_check_start_time_ = base::Time();
+    return;
+  }
+
+  for (const auto& param : intent.extra_params()) {
+    int64_t start_request_ms;
+    if (sscanf(param.c_str(), arc::kRequestStartTimeParamTemplate,
+               &start_request_ms) != 1)
+      continue;
+    const base::TimeDelta launch_time =
+        base::TimeTicks::Now() - base::TimeTicks() -
+        base::TimeDelta::FromMilliseconds(start_request_ms);
+    DCHECK_GE(launch_time, base::TimeDelta());
+    arc::UpdatePlayStoreLaunchTime(launch_time);
+  }
+}
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
index 0a5ad03..903051e 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
@@ -91,6 +91,7 @@
 
   void RegisterApp(AppWindowInfo* app_window_info);
   void UnregisterApp(AppWindowInfo* app_window_info);
+  void HandlePlayStoreLaunch(AppWindowInfo* app_window_info);
 
   AppWindowInfo* GetAppWindowInfoForTask(int task_id);
   ArcAppWindow* GetAppWindowForTask(int task_id);
diff --git a/chrome/browser/ui/ash/launcher/arc_shelf_spinner_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_shelf_spinner_item_controller.cc
index 3e6f5f9..2b5ad56 100644
--- a/chrome/browser/ui/ash/launcher/arc_shelf_spinner_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_shelf_spinner_item_controller.cc
@@ -5,16 +5,17 @@
 #include "chrome/browser/ui/ash/launcher/arc_shelf_spinner_item_controller.h"
 
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/launcher/shelf_spinner_controller.h"
 #include "components/arc/metrics/arc_metrics_constants.h"
 
 ArcShelfSpinnerItemController::ArcShelfSpinnerItemController(
     const std::string& arc_app_id,
     int event_flags,
+    arc::UserInteractionType user_interaction_type,
     int64_t display_id)
     : ShelfSpinnerItemController(arc_app_id),
       event_flags_(event_flags),
+      user_interaction_type_(user_interaction_type),
       display_id_(display_id) {
   arc::ArcSessionManager* arc_session_manager = arc::ArcSessionManager::Get();
   // arc::ArcSessionManager might not be set in tests.
@@ -57,7 +58,7 @@
 
   // Close() destroys this object, so start launching the app first.
   arc::LaunchApp(observed_profile_, arc_app_id, event_flags_,
-                 arc::UserInteractionType::APP_STARTED_FROM_SHELF, display_id_);
+                 user_interaction_type_, display_id_);
   Close();
 }
 
diff --git a/chrome/browser/ui/ash/launcher/arc_shelf_spinner_item_controller.h b/chrome/browser/ui/ash/launcher/arc_shelf_spinner_item_controller.h
index 07a160d..c253d22 100644
--- a/chrome/browser/ui/ash/launcher/arc_shelf_spinner_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/arc_shelf_spinner_item_controller.h
@@ -11,8 +11,10 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/launcher/shelf_spinner_item_controller.h"
 
 // ArcShelfSpinnerItemController displays the icon of the ARC app that
@@ -24,6 +26,7 @@
  public:
   ArcShelfSpinnerItemController(const std::string& arc_app_id,
                                 int event_flags,
+                                arc::UserInteractionType user_interaction_type,
                                 int64_t display_id);
 
   ~ArcShelfSpinnerItemController() override;
@@ -44,6 +47,9 @@
   // be propagated to the launch event once the app is actually launched.
   const int event_flags_;
 
+  // Stores how this action was initiated.
+  const arc::UserInteractionType user_interaction_type_;
+
   const int64_t display_id_;
 
   // Unowned
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index e6a437f..9f4bad9 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -11,15 +11,19 @@
 #include "ash/public/cpp/app_menu_constants.h"
 #include "ash/public/cpp/shelf_item_delegate.h"
 #include "ash/public/cpp/shelf_model.h"
+#include "ash/public/cpp/tablet_mode.h"
 #include "ash/public/cpp/window_properties.h"
+#include "ash/root_window_controller.h"
 #include "ash/shelf/home_button.h"
 #include "ash/shelf/overflow_button.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_app_button.h"
+#include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_view.h"
 #include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
@@ -54,6 +58,7 @@
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/test/test_app_window_icon_observer.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/test/web_app_install_observer.h"
@@ -62,6 +67,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chromeos/constants/chromeos_switches.h"
 #include "components/crx_file/id_util.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
@@ -78,6 +84,7 @@
 #include "ui/aura/window.h"
 #include "ui/base/base_window.h"
 #include "ui/base/window_open_disposition.h"
+#include "ui/display/display.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/screen.h"
 #include "ui/display/test/display_manager_test_api.h"
@@ -140,6 +147,35 @@
       .id();
 }
 
+void ExtendHotseat(Browser* browser) {
+  ash::RootWindowController* const controller =
+      ash::Shell::GetRootWindowControllerWithDisplayId(
+          display::Screen::GetScreen()->GetPrimaryDisplay().id());
+  EXPECT_EQ(ash::HotseatState::kHidden,
+            controller->shelf()->shelf_layout_manager()->hotseat_state());
+
+  BrowserView* const browser_view =
+      BrowserView::GetBrowserViewForBrowser(browser);
+  aura::Window* const browser_window =
+      browser_view->GetWidget()->GetNativeWindow();
+
+  const gfx::Rect display_bounds = display::Screen::GetScreen()
+                                       ->GetDisplayNearestWindow(browser_window)
+                                       .bounds();
+  const gfx::Point start_point = gfx::Point(
+      display_bounds.width() / 4,
+      display_bounds.bottom() - ash::ShelfConfig::Get()->shelf_size() / 2);
+  gfx::Point end_point(start_point);
+  end_point.set_y(10);
+
+  ui::test::EventGenerator event_generator(controller->GetRootWindow());
+  event_generator.GestureScrollSequence(
+      start_point, end_point, base::TimeDelta::FromMilliseconds(500), 4);
+
+  EXPECT_EQ(ash::HotseatState::kExtended,
+            controller->shelf()->shelf_layout_manager()->hotseat_state());
+}
+
 }  // namespace
 
 class LauncherPlatformAppBrowserTest
@@ -254,36 +290,6 @@
     return shelf_model()->GetItemIndexForType(type);
   }
 
-  // Try to rip off |item_index|.
-  void RipOffItemIndex(int index,
-                       ui::test::EventGenerator* generator,
-                       ash::ShelfViewTestAPI* test,
-                       RipOffCommand command) {
-    ash::ShelfAppButton* button = test->GetButton(index);
-    gfx::Point start_point = button->GetBoundsInScreen().CenterPoint();
-    gfx::Point rip_off_point(start_point.x(), 0);
-    generator->MoveMouseTo(start_point.x(), start_point.y());
-    base::RunLoop().RunUntilIdle();
-    generator->PressLeftButton();
-    base::RunLoop().RunUntilIdle();
-    generator->MoveMouseTo(rip_off_point.x(), rip_off_point.y());
-    base::RunLoop().RunUntilIdle();
-    test->RunMessageLoopUntilAnimationsDone();
-    if (command == RIP_OFF_ITEM_AND_RETURN) {
-      generator->MoveMouseTo(start_point.x(), start_point.y());
-      base::RunLoop().RunUntilIdle();
-      test->RunMessageLoopUntilAnimationsDone();
-    } else if (command == RIP_OFF_ITEM_AND_CANCEL) {
-      // This triggers an internal cancel. Using VKEY_ESCAPE was too unreliable.
-      button->OnMouseCaptureLost();
-    }
-    if (command != RIP_OFF_ITEM_AND_DONT_RELEASE_MOUSE) {
-      generator->ReleaseLeftButton();
-      base::RunLoop().RunUntilIdle();
-      test->RunMessageLoopUntilAnimationsDone();
-    }
-  }
-
   // Creates a context menu for the existing browser shortcut item.
   std::unique_ptr<LauncherContextMenu> CreateBrowserItemContextMenu() {
     int index = shelf_model()->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT);
@@ -1997,3 +2003,58 @@
   EXPECT_TRUE(
       shelf_model()->GetShelfItemDelegate(shelf_model()->items()[0].id));
 }
+
+class HotseatShelfAppBrowserTest : public ShelfAppBrowserTest {
+ public:
+  HotseatShelfAppBrowserTest() = default;
+  ~HotseatShelfAppBrowserTest() override = default;
+
+  // ShelfAppBrowserTest:
+  void SetUp() override {
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        chromeos::switches::kShelfHotseat);
+    ShelfAppBrowserTest::SetUp();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HotseatShelfAppBrowserTest);
+};
+
+// Tests that launching and switching apps by tapping shelf buttons hides the
+// hotseat.
+IN_PROC_BROWSER_TEST_F(HotseatShelfAppBrowserTest,
+                       TappingAppIconsHidesHotseat) {
+  ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+
+  // Create two apps, then extend the hotseat.
+  ash::ShelfID shortcut_id_1 = CreateShortcut("app1");
+  ash::ShelfID shortcut_id_2 = CreateShortcut("app2");
+  ExtendHotseat(browser());
+
+  // Launch app1, the hotseat should hide.
+  ash::RootWindowController* controller =
+      ash::Shell::GetRootWindowControllerWithDisplayId(
+          display::Screen::GetScreen()->GetPrimaryDisplay().id());
+  ash::ShelfView* shelf_view = controller->shelf()->GetShelfViewForTesting();
+  views::View* button_1 = shelf_view->GetShelfAppButton(shortcut_id_1);
+  ui::test::EventGenerator event_generator(controller->GetRootWindow());
+  event_generator.GestureTapAt(button_1->GetBoundsInScreen().CenterPoint());
+
+  EXPECT_EQ(ash::HotseatState::kHidden,
+            controller->shelf()->shelf_layout_manager()->hotseat_state());
+
+  // Show the hotseat again, and launch app2. The hotseat should hide again.
+  ExtendHotseat(browser());
+  views::View* button_2 = shelf_view->GetShelfAppButton(shortcut_id_2);
+  event_generator.GestureTapAt(button_2->GetBoundsInScreen().CenterPoint());
+
+  EXPECT_EQ(ash::HotseatState::kHidden,
+            controller->shelf()->shelf_layout_manager()->hotseat_state());
+
+  // Extend the hotseat and test that switching back to app1 results in a hidden
+  // hotseat.
+  ExtendHotseat(browser());
+  event_generator.GestureTapAt(button_1->GetBoundsInScreen().CenterPoint());
+  EXPECT_EQ(ash::HotseatState::kHidden,
+            controller->shelf()->shelf_layout_manager()->hotseat_state());
+}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index f6f9a75..eea93a6 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -33,6 +33,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/statistics_recorder.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
@@ -4343,6 +4344,69 @@
       arc::kPlayStoreAppId));
 }
 
+TEST_F(ChromeLauncherControllerArcDefaultAppsTest, PlayStoreLaunchMetric) {
+  extension_service_->AddExtension(arc_support_host_.get());
+  arc_test_.SetUp(profile());
+  ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
+
+  InitLauncherController();
+  EnablePlayStore(true);
+
+  // Play Store available now as a default app but is not ready yet.
+  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
+      prefs->GetApp(arc::kPlayStoreAppId);
+  ASSERT_TRUE(app_info);
+  EXPECT_FALSE(app_info->ready);
+
+  constexpr char kHistogramName[] = "Arc.PlayStoreLaunch.TimeDelta";
+
+  // Launch Play Store in deferred mode.
+  arc::LaunchApp(profile(), arc::kPlayStoreAppId, ui::EF_LEFT_MOUSE_BUTTON,
+                 arc::UserInteractionType::NOT_USER_INITIATED);
+  // This is deferred launch, no actual intents are delivered to ARC.
+  EXPECT_EQ(0U, arc_test_.app_instance()->launch_intents().size());
+  arc::mojom::AppInfo app;
+  app.activity = arc::kPlayStoreActivity;
+  app.package_name = arc::kPlayStorePackage;
+  const base::TimeTicks app_ready_ticks = base::TimeTicks::Now();
+  arc_test_.app_instance()->SendRefreshAppList({app});
+  ASSERT_EQ(1U, arc_test_.app_instance()->launch_intents().size());
+  std::string play_store_window_id("org.chromium.arc.1");
+  views::Widget* play_store_window = CreateArcWindow(play_store_window_id);
+  arc_test_.app_instance()->SendTaskCreated(
+      1, app, arc_test_.app_instance()->launch_intents()[0]);
+  const base::TimeTicks app_launched_ticks = base::TimeTicks::Now();
+  EXPECT_TRUE(
+      launcher_controller_->GetItem(ash::ShelfID(arc::kPlayStoreAppId)));
+  // UMA is reported since app becomes ready.
+  base::HistogramBase* const histogram =
+      base::StatisticsRecorder::FindHistogram(kHistogramName);
+  ASSERT_TRUE(histogram);
+  // Recorded time should not be longer than
+  // app_launched_ticks - app_ready_ticks, the indication that app launch time
+  // was recorded since app became ready.
+  std::unique_ptr<base::HistogramSamples> samples = histogram->SnapshotDelta();
+  ASSERT_EQ(1, samples->TotalCount());
+  EXPECT_GE((app_launched_ticks - app_ready_ticks).InMilliseconds(),
+            samples->sum());
+  play_store_window->Close();
+
+  // Launch Play Store in app-ready mode.
+  arc::LaunchApp(profile(), arc::kPlayStoreAppId, ui::EF_LEFT_MOUSE_BUTTON,
+                 arc::UserInteractionType::NOT_USER_INITIATED);
+  ASSERT_EQ(2U, arc_test_.app_instance()->launch_intents().size());
+  play_store_window_id = "org.chromium.arc.2";
+  play_store_window = CreateArcWindow(play_store_window_id);
+  arc_test_.app_instance()->SendTaskCreated(
+      2, app, arc_test_.app_instance()->launch_intents()[1]);
+  EXPECT_TRUE(
+      launcher_controller_->GetItem(ash::ShelfID(arc::kPlayStoreAppId)));
+  // UMA is reported for app-ready launch. Note, previous call of SnapshotDelta
+  // resets samples, so we expect here only one recorded.
+  EXPECT_EQ(1, histogram->SnapshotDelta()->TotalCount());
+  play_store_window->Close();
+}
+
 // Tests that the Play Store is not visible in AOSP image and visible in default
 // images.
 TEST_P(ChromeLauncherControllerPlayStoreAvailabilityTest, Visible) {
diff --git a/chrome/browser/ui/autofill/autofill_bubble_handler.h b/chrome/browser/ui/autofill/autofill_bubble_handler.h
new file mode 100644
index 0000000..c3a4550
--- /dev/null
+++ b/chrome/browser/ui/autofill/autofill_bubble_handler.h
@@ -0,0 +1,51 @@
+// Copyright (c) 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_AUTOFILL_AUTOFILL_BUBBLE_HANDLER_H_
+#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_BUBBLE_HANDLER_H_
+
+#include "base/macros.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace autofill {
+class LocalCardMigrationBubble;
+class LocalCardMigrationBubbleController;
+class SaveCardBubbleView;
+class SaveCardBubbleController;
+
+// Responsible for receiving calls from controllers and showing autofill
+// bubbles.
+class AutofillBubbleHandler {
+ public:
+  AutofillBubbleHandler() = default;
+  virtual ~AutofillBubbleHandler() = default;
+
+  virtual SaveCardBubbleView* ShowSaveCreditCardBubble(
+      content::WebContents* web_contents,
+      SaveCardBubbleController* controller,
+      bool is_user_gesture) = 0;
+
+  virtual LocalCardMigrationBubble* ShowLocalCardMigrationBubble(
+      content::WebContents* web_contents,
+      LocalCardMigrationBubbleController* controller,
+      bool is_user_gesture) = 0;
+
+  // TODO(crbug.com/964127): Wait for the integration with sign in after local
+  // save to be landed to see if we need to merge password saved and credit card
+  // saved functions.
+  virtual void OnPasswordSaved() = 0;
+
+  // TODO(crbug.com/964127): Move password bubble here.
+  // TODO(crbug.com/964127): Add ShowSyncPromoBubble().
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AutofillBubbleHandler);
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_BUBBLE_HANDLER_H_
diff --git a/chrome/browser/ui/autofill/payments/local_card_migration_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/local_card_migration_bubble_controller_impl.cc
index 2e5a2b5b5..580799c 100644
--- a/chrome/browser/ui/autofill/payments/local_card_migration_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/local_card_migration_bubble_controller_impl.cc
@@ -8,6 +8,7 @@
 
 #include "chrome/browser/autofill/strike_database_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_handler.h"
 #include "chrome/browser/ui/autofill/payments/local_card_migration_bubble.h"
 #include "chrome/browser/ui/autofill/payments/payments_ui_constants.h"
 #include "chrome/browser/ui/browser.h"
@@ -174,8 +175,9 @@
 
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   local_card_migration_bubble_ =
-      browser->window()->ShowLocalCardMigrationBubble(web_contents(), this,
-                                                      is_reshow_);
+      browser->window()
+          ->GetAutofillBubbleHandler()
+          ->ShowLocalCardMigrationBubble(web_contents(), this, is_reshow_);
   DCHECK(local_card_migration_bubble_);
   UpdateLocalCardMigrationIcon();
   timer_ = std::make_unique<base::ElapsedTimer>();
diff --git a/chrome/browser/ui/autofill/payments/local_card_migration_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/payments/local_card_migration_bubble_controller_impl_unittest.cc
index 46350f2..409555d 100644
--- a/chrome/browser/ui/autofill/payments/local_card_migration_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/payments/local_card_migration_bubble_controller_impl_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/values.h"
 #include "chrome/browser/ui/autofill/payments/local_card_migration_bubble.h"
+#include "chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -59,26 +60,6 @@
   base::TimeDelta elapsed_;
 };
 
-class TestLocalCardMigrationBubble final : public LocalCardMigrationBubble {
-  void Hide() override {}
-};
-
-class LocalCardMigrationBubbleTestBrowserWindow : public TestBrowserWindow {
- public:
-  LocalCardMigrationBubble* ShowLocalCardMigrationBubble(
-      content::WebContents* contents,
-      LocalCardMigrationBubbleController* controller,
-      bool user_gesture) override {
-    test_local_card_migration_bubble_ =
-        std::make_unique<TestLocalCardMigrationBubble>();
-    return test_local_card_migration_bubble_.get();
-  }
-
- private:
-  std::unique_ptr<TestLocalCardMigrationBubble>
-      test_local_card_migration_bubble_;
-};
-
 }  // namespace
 
 class LocalCardMigrationBubbleControllerImplTest
@@ -94,10 +75,6 @@
     TestLocalCardMigrationBubbleControllerImpl::CreateForTesting(web_contents);
   }
 
-  std::unique_ptr<BrowserWindow> CreateBrowserWindow() override {
-    return std::make_unique<LocalCardMigrationBubbleTestBrowserWindow>();
-  }
-
  protected:
   void ShowBubble() {
     controller()->ShowBubble(base::BindOnce(&LocalCardMigrationCallback));
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
index 330b95f..756db08 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_handler.h"
 #include "chrome/browser/ui/autofill/payments/payments_ui_constants.h"
 #include "chrome/browser/ui/autofill/payments/save_card_bubble_view.h"
 #include "chrome/browser/ui/autofill/payments/save_card_ui.h"
@@ -761,8 +762,9 @@
   UpdateSaveCardIcon();
 
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
-  save_card_bubble_view_ = browser->window()->ShowSaveCreditCardBubble(
-      web_contents(), this, is_reshow_);
+  save_card_bubble_view_ =
+      browser->window()->GetAutofillBubbleHandler()->ShowSaveCreditCardBubble(
+          web_contents(), this, is_reshow_);
   DCHECK(save_card_bubble_view_);
 
   // Update icon after creating |save_card_bubble_view_| so that icon will show
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc
index 8209987..ece4a678 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/values.h"
 #include "chrome/browser/ui/autofill/payments/save_card_bubble_view.h"
 #include "chrome/browser/ui/autofill/payments/save_card_ui.h"
+#include "chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -93,10 +94,6 @@
             prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE);
   }
 
-  std::unique_ptr<BrowserWindow> CreateBrowserWindow() override {
-    return std::make_unique<SaveCardBubbleTestBrowserWindow>();
-  }
-
   void SetLegalMessage(
       const std::string& message_json,
       AutofillClient::SaveCreditCardOptions options =
@@ -157,25 +154,6 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 
  private:
-  class TestSaveCardBubbleView final : public SaveCardBubbleView {
-    void Hide() override {}
-  };
-
-  class SaveCardBubbleTestBrowserWindow : public TestBrowserWindow {
-   public:
-    SaveCardBubbleView* ShowSaveCreditCardBubble(
-        content::WebContents* contents,
-        SaveCardBubbleController* controller,
-        bool user_gesture) override {
-      if (!save_card_bubble_view_)
-        save_card_bubble_view_ = std::make_unique<TestSaveCardBubbleView>();
-      return save_card_bubble_view_.get();
-    }
-
-   private:
-    std::unique_ptr<TestSaveCardBubbleView> save_card_bubble_view_;
-  };
-
   static void UploadSaveCardCallback(
       AutofillClient::SaveCardOfferUserDecision user_decision,
       const AutofillClient::UserProvidedCardDetails&
diff --git a/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc
new file mode 100644
index 0000000..4e05b3d
--- /dev/null
+++ b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 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/autofill/test/test_autofill_bubble_handler.h"
+
+namespace autofill {
+
+TestAutofillBubbleHandler::TestAutofillBubbleHandler() = default;
+
+TestAutofillBubbleHandler::~TestAutofillBubbleHandler() = default;
+
+SaveCardBubbleView* TestAutofillBubbleHandler::ShowSaveCreditCardBubble(
+    content::WebContents* web_contents,
+    SaveCardBubbleController* controller,
+    bool is_user_gesture) {
+  if (!save_card_bubble_view_)
+    save_card_bubble_view_ = std::make_unique<TestSaveCardBubbleView>();
+  return save_card_bubble_view_.get();
+}
+
+LocalCardMigrationBubble*
+TestAutofillBubbleHandler::ShowLocalCardMigrationBubble(
+    content::WebContents* web_contents,
+    LocalCardMigrationBubbleController* controller,
+    bool is_user_gesture) {
+  if (!local_card_migration_bubble_view_) {
+    local_card_migration_bubble_view_ =
+        std::make_unique<TestLocalCardMigrationBubbleView>();
+  }
+  return local_card_migration_bubble_view_.get();
+}
+
+void TestAutofillBubbleHandler::OnPasswordSaved() {}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h
new file mode 100644
index 0000000..149e72c
--- /dev/null
+++ b/chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h
@@ -0,0 +1,51 @@
+// Copyright (c) 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_AUTOFILL_TEST_TEST_AUTOFILL_BUBBLE_HANDLER_H_
+#define CHROME_BROWSER_UI_AUTOFILL_TEST_TEST_AUTOFILL_BUBBLE_HANDLER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_handler.h"
+#include "chrome/browser/ui/autofill/payments/local_card_migration_bubble.h"
+#include "chrome/browser/ui/autofill/payments/save_card_bubble_view.h"
+
+namespace autofill {
+
+class TestLocalCardMigrationBubbleView final : public LocalCardMigrationBubble {
+  void Hide() override {}
+};
+
+class TestSaveCardBubbleView final : public SaveCardBubbleView {
+  void Hide() override {}
+};
+
+class TestAutofillBubbleHandler : public AutofillBubbleHandler {
+ public:
+  TestAutofillBubbleHandler();
+  ~TestAutofillBubbleHandler() override;
+
+  // AutofillBubbleHandler:
+  SaveCardBubbleView* ShowSaveCreditCardBubble(
+      content::WebContents* web_contents,
+      SaveCardBubbleController* controller,
+      bool is_user_gesture) override;
+  LocalCardMigrationBubble* ShowLocalCardMigrationBubble(
+      content::WebContents* web_contents,
+      LocalCardMigrationBubbleController* controller,
+      bool is_user_gesture) override;
+  void OnPasswordSaved() override;
+
+ private:
+  std::unique_ptr<TestLocalCardMigrationBubbleView>
+      local_card_migration_bubble_view_;
+  std::unique_ptr<TestSaveCardBubbleView> save_card_bubble_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestAutofillBubbleHandler);
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_TEST_TEST_AUTOFILL_BUBBLE_HANDLER_H_
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 33b26f6..134df162 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -45,10 +45,7 @@
 class ToolbarActionsBar;
 
 namespace autofill {
-class LocalCardMigrationBubbleController;
-class LocalCardMigrationBubble;
-class SaveCardBubbleController;
-class SaveCardBubbleView;
+class AutofillBubbleHandler;
 }  // namespace autofill
 
 namespace content {
@@ -253,8 +250,9 @@
   // the window. Returns whether any change occurred.
   virtual bool UpdatePageActionIcon(PageActionIconType type) = 0;
 
-  // Executes highlight animation on toolbar's avatar.
-  virtual void ShowAvatarHighlightAnimation() = 0;
+  // Returns the AutofillBubbleHandler responsible for handling all
+  // Autofill-related bubbles.
+  virtual autofill::AutofillBubbleHandler* GetAutofillBubbleHandler() = 0;
 
   // Executes the action for the specified page action icon.
   virtual void ExecutePageActionIconForTesting(PageActionIconType type) = 0;
@@ -365,18 +363,6 @@
       qrcode_generator::QRCodeGeneratorBubbleController* controller,
       const GURL& url) = 0;
 
-  // Shows the "Save credit card" bubble.
-  virtual autofill::SaveCardBubbleView* ShowSaveCreditCardBubble(
-      content::WebContents* contents,
-      autofill::SaveCardBubbleController* controller,
-      bool is_user_gesture) = 0;
-
-  // Shows the local card migration bubble.
-  virtual autofill::LocalCardMigrationBubble* ShowLocalCardMigrationBubble(
-      content::WebContents* contents,
-      autofill::LocalCardMigrationBubbleController* controller,
-      bool is_user_gesture) = 0;
-
   // Shows the "send tab to self" bubble.
   virtual send_tab_to_self::SendTabToSelfBubbleView* ShowSendTabToSelfBubble(
       content::WebContents* contents,
diff --git a/chrome/browser/ui/cocoa/color_chooser_mac.h b/chrome/browser/ui/cocoa/color_chooser_mac.h
index 64da207..5bcbf720 100644
--- a/chrome/browser/ui/cocoa/color_chooser_mac.h
+++ b/chrome/browser/ui/cocoa/color_chooser_mac.h
@@ -11,7 +11,8 @@
 #include "components/remote_cocoa/common/color_panel.mojom.h"
 #include "content/public/browser/color_chooser.h"
 #include "content/public/browser/web_contents.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 class ColorChooserMac : public content::ColorChooser,
                         public remote_cocoa::mojom::ColorPanelHost {
@@ -40,8 +41,8 @@
   // outlive this class.
   content::WebContents* web_contents_;
 
-  remote_cocoa::mojom::ColorPanelPtr mojo_panel_ptr_;
-  mojo::Binding<remote_cocoa::mojom::ColorPanelHost> mojo_host_binding_;
+  mojo::Remote<remote_cocoa::mojom::ColorPanel> mojo_panel_remote_;
+  mojo::Receiver<remote_cocoa::mojom::ColorPanelHost> mojo_host_receiver_{this};
   DISALLOW_COPY_AND_ASSIGN(ColorChooserMac);
 };
 
diff --git a/chrome/browser/ui/cocoa/color_chooser_mac.mm b/chrome/browser/ui/cocoa/color_chooser_mac.mm
index fca16f9..509121c 100644
--- a/chrome/browser/ui/cocoa/color_chooser_mac.mm
+++ b/chrome/browser/ui/cocoa/color_chooser_mac.mm
@@ -9,8 +9,7 @@
 #include "components/remote_cocoa/app_shim/color_panel_bridge.h"
 #include "components/remote_cocoa/browser/application_host.h"
 #include "components/remote_cocoa/browser/window.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "skia/ext/skia_utils_mac.h"
 
 namespace {
@@ -32,20 +31,20 @@
 
 ColorChooserMac::ColorChooserMac(content::WebContents* web_contents,
                                  SkColor initial_color)
-    : web_contents_(web_contents), mojo_host_binding_(this) {
-  remote_cocoa::mojom::ColorPanelHostPtr mojo_host_ptr;
-  mojo_host_binding_.Bind(mojo::MakeRequest(&mojo_host_ptr));
+    : web_contents_(web_contents) {
   auto* application_host = remote_cocoa::ApplicationHost::GetForNativeView(
       web_contents ? web_contents->GetNativeView() : gfx::NativeView());
   if (application_host) {
     application_host->GetApplication()->ShowColorPanel(
-        mojo::MakeRequest(&mojo_panel_ptr_), std::move(mojo_host_ptr));
+        mojo_panel_remote_.BindNewPipeAndPassReceiver(),
+        mojo_host_receiver_.BindNewPipeAndPassRemote());
   } else {
-    mojo::MakeStrongBinding(std::make_unique<remote_cocoa::ColorPanelBridge>(
-                                std::move(mojo_host_ptr)),
-                            mojo::MakeRequest(&mojo_panel_ptr_));
+    mojo::MakeSelfOwnedReceiver(
+        std::make_unique<remote_cocoa::ColorPanelBridge>(
+            mojo_host_receiver_.BindNewPipeAndPassRemote()),
+        mojo_panel_remote_.BindNewPipeAndPassReceiver());
   }
-  mojo_panel_ptr_->Show(initial_color);
+  mojo_panel_remote_->Show(initial_color);
 }
 
 ColorChooserMac::~ColorChooserMac() {
@@ -73,7 +72,7 @@
 }
 
 void ColorChooserMac::SetSelectedColor(SkColor color) {
-  mojo_panel_ptr_->SetSelectedColor(color);
+  mojo_panel_remote_->SetSelectedColor(color);
 }
 
 namespace chrome {
diff --git a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h
index 716bd60..0e644f7 100644
--- a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h
@@ -14,6 +14,7 @@
 #include "components/app_modal/native_app_modal_dialog.h"
 #include "components/remote_cocoa/app_shim/alert.h"
 #include "components/remote_cocoa/common/alert.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 class PopunderPreventer;
 
@@ -52,10 +53,10 @@
 
   // Called if there is an error connecting to the alert process. Deletes
   // |this|.
-  void OnConnectionError();
+  void OnMojoDisconnect();
 
   // Mojo interface to the NSAlert.
-  remote_cocoa::mojom::AlertBridgePtr alert_bridge_;
+  mojo::Remote<remote_cocoa::mojom::AlertBridge> alert_bridge_;
 
   std::unique_ptr<app_modal::JavaScriptAppModalDialog> dialog_;
   std::unique_ptr<PopunderPreventer> popunder_preventer_;
diff --git a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
index 995cc415..84dbc1b 100644
--- a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
@@ -22,6 +22,7 @@
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/ui_base_types.h"
@@ -109,7 +110,7 @@
   delete this;
 }
 
-void JavaScriptAppModalDialogCocoa::OnConnectionError() {
+void JavaScriptAppModalDialogCocoa::OnMojoDisconnect() {
   dialog()->OnClose();
   delete this;
 }
@@ -134,10 +135,10 @@
 void JavaScriptAppModalDialogCocoa::ShowAppModalDialog() {
   is_showing_ = true;
 
-  remote_cocoa::mojom::AlertBridgeRequest bridge_request =
-      mojo::MakeRequest(&alert_bridge_);
-  alert_bridge_.set_connection_error_handler(
-      base::BindOnce(&JavaScriptAppModalDialogCocoa::OnConnectionError,
+  mojo::PendingReceiver<remote_cocoa::mojom::AlertBridge> bridge_receiver =
+      alert_bridge_.BindNewPipeAndPassReceiver();
+  alert_bridge_.set_disconnect_handler(
+      base::BindOnce(&JavaScriptAppModalDialogCocoa::OnMojoDisconnect,
                      weak_factory_.GetWeakPtr()));
   // If the alert is from a window that is out of process then use the
   // remote_cocoa::ApplicationHost for that window to create the alert.
@@ -146,9 +147,9 @@
   auto* application_host = remote_cocoa::ApplicationHost::GetForNativeView(
       dialog_->web_contents()->GetNativeView());
   if (application_host)
-    application_host->GetApplication()->CreateAlert(std::move(bridge_request));
+    application_host->GetApplication()->CreateAlert(std::move(bridge_receiver));
   else
-    ignore_result(new remote_cocoa::AlertBridge(std::move(bridge_request)));
+    ignore_result(new remote_cocoa::AlertBridge(std::move(bridge_receiver)));
   alert_bridge_->Show(
       GetAlertParams(),
       base::BindOnce(&JavaScriptAppModalDialogCocoa::OnAlertFinished,
diff --git a/chrome/browser/ui/libgtkui/BUILD.gn b/chrome/browser/ui/libgtkui/BUILD.gn
index 26e8390..b1b8e33 100644
--- a/chrome/browser/ui/libgtkui/BUILD.gn
+++ b/chrome/browser/ui/libgtkui/BUILD.gn
@@ -20,7 +20,6 @@
     "gtk_util.h",
     "input_method_context_impl_gtk.cc",
     "input_method_context_impl_gtk.h",
-    "libgtkui_export.h",
     "native_theme_gtk.cc",
     "native_theme_gtk.h",
     "nav_button_provider_gtk.cc",
@@ -37,16 +36,9 @@
     "settings_provider.h",
     "settings_provider_gtk.cc",
     "settings_provider_gtk.h",
-    "skia_utils_gtk.cc",
-    "skia_utils_gtk.h",
-    "unity_service.cc",
-    "unity_service.h",
   ]
 
-  configs += [
-    "//build/config/linux/pangocairo",
-    "//build/config/linux:x11",
-  ]
+  configs += [ "//build/config/linux/pangocairo" ]
 
   if (use_gio) {
     sources += [
@@ -60,26 +52,15 @@
     configs += [ "//printing:cups" ]
   }
 
-  defines = [ "LIBGTKUI_IMPLEMENTATION" ]
+  defines = [ "IS_LIBGTKUI_IMPL" ]
 
   deps = [
     "//base",
-    "//base:i18n",
-    "//base/third_party/dynamic_annotations",
-    "//build:branding_buildflags",
     "//build/config/linux/gtk",
     "//build/config/linux/gtk:gtkprint",
-    "//cc/paint",
-    "//chrome:extra_resources",
-    "//chrome:resources",
-    "//chrome:strings",
-    "//chrome/app:command_ids",
-    "//chrome/app/theme:theme_resources",
     "//chrome/browser/ui/views",
-    "//chrome/common:buildflags",
     "//chrome/common:constants",
     "//components/prefs",
-    "//components/resources",
     "//content/public/browser",
     "//printing",
     "//skia",
@@ -96,11 +77,9 @@
     "//ui/events",
     "//ui/events:dom_keyboard_layout",
     "//ui/events:dom_keycode_converter",
-    "//ui/events:events_base",
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/native_theme",
-    "//ui/resources",
     "//ui/shell_dialogs",
     "//ui/strings",
     "//ui/views",
@@ -115,6 +94,8 @@
       "gtk_event_loop_x11.h",
     ]
 
+    configs += [ "//build/config/linux:x11" ]
+
     defines += [ "USE_GTK_EVENT_LOOP_X11" ]
 
     deps += [
diff --git a/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.cc b/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.cc
index fe74992..d63bdcb 100644
--- a/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.cc
+++ b/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.cc
@@ -355,7 +355,7 @@
 void GtkKeyBindingsHandler::MoveViewport(GtkTextView* text_view,
                                          GtkScrollStep step,
                                          gint count) {
-  // Not supported by webkit.
+  // Not supported by Blink.
 }
 
 void GtkKeyBindingsHandler::PasteClipboard(GtkTextView* text_view) {
@@ -375,11 +375,11 @@
 }
 
 void GtkKeyBindingsHandler::ToggleCursorVisible(GtkTextView* text_view) {
-  // Not supported by webkit.
+  // Not supported by Blink.
 }
 
 void GtkKeyBindingsHandler::ToggleOverwrite(GtkTextView* text_view) {
-  // Not supported by webkit.
+  // Not supported by Blink.
 }
 
 #if !GTK_CHECK_VERSION(3, 90, 0)
diff --git a/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.h b/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.h
index 8a9bc3c..bb370736 100644
--- a/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.h
+++ b/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.h
@@ -34,10 +34,8 @@
 // class derived from GtkTextView is used, which overrides all signals related
 // to key bindings, to make sure GtkTextView won't receive them.
 //
-// See third_party/WebKit/Source/WebCore/editing/EditorCommand.cpp for detailed
-// definition of webkit edit commands.
-// See webkit/glue/editor_client_impl.cc for key bindings predefined in our
-// webkit glue.
+// See third_party/blink/renderer/core/editing/commands/editor_command.cc for
+// detailed definition of Blink edit commands.
 class GtkKeyBindingsHandler {
  public:
   GtkKeyBindingsHandler();
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.cc b/chrome/browser/ui/libgtkui/gtk_ui.cc
index 860292e2..4f5624d 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.cc
+++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -16,7 +16,6 @@
 #include "base/containers/flat_map.h"
 #include "base/debug/leak_annotations.h"
 #include "base/environment.h"
-#include "base/i18n/rtl.h"
 #include "base/logging.h"
 #include "base/nix/mime_util_xdg.h"
 #include "base/nix/xdg_util.h"
@@ -33,8 +32,6 @@
 #include "chrome/browser/ui/libgtkui/printing_gtk_util.h"
 #include "chrome/browser/ui/libgtkui/select_file_dialog_impl.h"
 #include "chrome/browser/ui/libgtkui/settings_provider_gtk.h"
-#include "chrome/browser/ui/libgtkui/skia_utils_gtk.h"
-#include "chrome/browser/ui/libgtkui/unity_service.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "printing/buildflags/buildflags.h"
@@ -45,7 +42,6 @@
 #include "ui/base/ime/linux/fake_input_method_context.h"
 #include "ui/base/ime/linux/linux_input_method_context.h"
 #include "ui/base/ime/linux/linux_input_method_context_factory.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/display/display.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/dom_keyboard_layout_manager.h"
@@ -65,7 +61,6 @@
 #include "ui/views/controls/button/label_button_border.h"
 #include "ui/views/linux_ui/device_scale_factor_observer.h"
 #include "ui/views/linux_ui/window_button_order_observer.h"
-#include "ui/views/resources/grit/views_resources.h"
 
 #if defined(USE_GIO)
 #include "chrome/browser/ui/libgtkui/settings_provider_gsettings.h"
@@ -90,14 +85,6 @@
 #include "chrome/browser/ui/views/nav_button_provider.h"
 #endif
 
-// A minimized port of GtkThemeService into something that can provide colors
-// and images for aura.
-//
-// TODO(erg): There's still a lot that needs ported or done for the first time:
-//
-// - Render and inject the omnibox background.
-// - Make sure to test with a light on dark theme, too.
-
 namespace libgtkui {
 
 namespace {
@@ -339,6 +326,61 @@
 }
 #endif  // defined(USE_GTK_EVENT_LOOP_X11)
 
+const SkBitmap GdkPixbufToSkBitmap(GdkPixbuf* pixbuf) {
+  // TODO(erg): What do we do in the case where the pixbuf fails these dchecks?
+  // I would prefer to use our gtk based canvas, but that would require
+  // recompiling half of our skia extensions with gtk support, which we can't
+  // do in this build.
+  DCHECK_EQ(GDK_COLORSPACE_RGB, gdk_pixbuf_get_colorspace(pixbuf));
+
+  int n_channels = gdk_pixbuf_get_n_channels(pixbuf);
+  int w = gdk_pixbuf_get_width(pixbuf);
+  int h = gdk_pixbuf_get_height(pixbuf);
+
+  SkBitmap ret;
+  ret.allocN32Pixels(w, h);
+  ret.eraseColor(0);
+
+  uint32_t* skia_data = static_cast<uint32_t*>(ret.getAddr(0, 0));
+
+  if (n_channels == 4) {
+    int total_length = w * h;
+    guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
+
+    // Now here's the trick: we need to convert the gdk data (which is RGBA and
+    // isn't premultiplied) to skia (which can be anything and premultiplied).
+    for (int i = 0; i < total_length; ++i, gdk_pixels += 4) {
+      const unsigned char& red = gdk_pixels[0];
+      const unsigned char& green = gdk_pixels[1];
+      const unsigned char& blue = gdk_pixels[2];
+      const unsigned char& alpha = gdk_pixels[3];
+
+      skia_data[i] = SkPreMultiplyARGB(alpha, red, green, blue);
+    }
+  } else if (n_channels == 3) {
+    // Because GDK makes rowstrides word aligned, we need to do something a bit
+    // more complex when a pixel isn't perfectly a word of memory.
+    int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+    guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
+    for (int y = 0; y < h; ++y) {
+      int row = y * rowstride;
+
+      for (int x = 0; x < w; ++x) {
+        guchar* pixel = gdk_pixels + row + (x * 3);
+        const unsigned char& red = pixel[0];
+        const unsigned char& green = pixel[1];
+        const unsigned char& blue = pixel[2];
+
+        skia_data[y * w + x] = SkPreMultiplyARGB(255, red, green, blue);
+      }
+    }
+  } else {
+    NOTREACHED();
+  }
+
+  return ret;
+}
+
 }  // namespace
 
 GtkUi::GtkUi() {
@@ -494,8 +536,7 @@
 
   // Dividing GTK's cursor blink cycle time (in milliseconds) by this value
   // yields an appropriate value for
-  // blink::mojom::RendererPreferences::caret_blink_interval.  This
-  // matches the logic in the WebKit GTK port.
+  // blink::mojom::RendererPreferences::caret_blink_interval.
   static const double kGtkCursorBlinkCycleFactor = 2000.0;
 
   gint cursor_blink_time = kGtkDefaultCursorBlinkTime;
@@ -543,16 +584,6 @@
   return false;
 }
 
-void GtkUi::SetDownloadCount(int count) const {
-  if (unity::IsRunning())
-    unity::SetDownloadCount(count);
-}
-
-void GtkUi::SetProgressFraction(float percentage) const {
-  if (unity::IsRunning())
-    unity::SetProgressFraction(percentage);
-}
-
 gfx::Image GtkUi::GetIconForContentType(const std::string& content_type,
                                         int size) const {
   // This call doesn't take a reference.
@@ -571,7 +602,7 @@
     if (!pixbuf)
       continue;
 
-    SkBitmap bitmap = GdkPixbufToImageSkia(pixbuf.get());
+    SkBitmap bitmap = GdkPixbufToSkBitmap(pixbuf.get());
     DCHECK_EQ(size, bitmap.width());
     DCHECK_EQ(size, bitmap.height());
     gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
@@ -848,7 +879,7 @@
   colors_[ThemeProperties::COLOR_NTP_LINK] = native_theme_->GetSystemColor(
       ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused);
 
-  // Generate the colors that we pass to WebKit.
+  // Generate the colors that we pass to Blink.
   focus_ring_color_ = native_theme_->GetSystemColor(
       ui::NativeTheme::kColorId_FocusedBorderColor);
 
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.h b/chrome/browser/ui/libgtkui/gtk_ui.h
index 44ad6106..545a0d3e 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.h
+++ b/chrome/browser/ui/libgtkui/gtk_ui.h
@@ -10,10 +10,10 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "build/buildflag.h"
-#include "chrome/browser/ui/libgtkui/libgtkui_export.h"
 #include "ui/base/glib/glib_signal.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/views/linux_ui/linux_ui.h"
@@ -81,8 +81,6 @@
   ui::NativeTheme* GetNativeTheme(aura::Window* window) const override;
   void SetNativeThemeOverride(NativeThemeGetter callback) override;
   bool GetDefaultUsesSystemTheme() const override;
-  void SetDownloadCount(int count) const override;
-  void SetProgressFraction(float percentage) const override;
   gfx::Image GetIconForContentType(const std::string& content_type,
                                    int size) const override;
   std::unique_ptr<views::Border> CreateNativeBorder(
@@ -126,7 +124,7 @@
   void LoadGtkValues();
 
   // Extracts colors and tints from the GTK theme, both for the
-  // ThemeService interface and the colors we send to webkit.
+  // ThemeService interface and the colors we send to Blink.
   void UpdateColors();
 
   // Sets the Xcursor theme and size with the GTK theme and size.
@@ -154,7 +152,7 @@
   // system-rendered borders and titlebar.
   ColorMap native_frame_colors_;
 
-  // Colors that we pass to WebKit. These are generated each time the theme
+  // Colors that we pass to Blink. These are generated each time the theme
   // changes.
   SkColor focus_ring_color_;
   SkColor active_selection_bg_color_;
@@ -205,6 +203,6 @@
 }  // namespace libgtkui
 
 // Access point to the GTK desktop system.
-LIBGTKUI_EXPORT views::LinuxUI* BuildGtkUi();
+COMPONENT_EXPORT(LIBGTKUI) views::LinuxUI* BuildGtkUi();
 
 #endif  // CHROME_BROWSER_UI_LIBGTKUI_GTK_UI_H_
diff --git a/chrome/browser/ui/libgtkui/gtk_util.cc b/chrome/browser/ui/libgtkui/gtk_util.cc
index c9d6229..4271533d 100644
--- a/chrome/browser/ui/libgtkui/gtk_util.cc
+++ b/chrome/browser/ui/libgtkui/gtk_util.cc
@@ -20,7 +20,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/string_util.h"
-#include "build/branding_buildflags.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/events/event.h"
@@ -138,54 +137,6 @@
   CommonInitFromCommandLine(command_line);
 }
 
-// TODO(erg): This method was copied out of shell_integration_linux.cc. Because
-// of how this library is structured as a stand alone .so, we can't call code
-// from browser and above.
-std::string GetDesktopName(base::Environment* env) {
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-  return "google-chrome.desktop";
-#else  // BUILDFLAG(CHROMIUM_BRANDING)
-  // Allow $CHROME_DESKTOP to override the built-in value, so that development
-  // versions can set themselves as the default without interfering with
-  // non-official, packaged versions using the built-in value.
-  std::string name;
-  if (env->GetVar("CHROME_DESKTOP", &name) && !name.empty())
-    return name;
-  return "chromium-browser.desktop";
-#endif
-}
-
-GdkModifierType GetGdkModifierForAccelerator(
-    const ui::Accelerator& accelerator) {
-  int event_flag = accelerator.modifiers();
-  int modifier = 0;
-  if (event_flag & ui::EF_SHIFT_DOWN)
-    modifier |= GDK_SHIFT_MASK;
-  if (event_flag & ui::EF_CONTROL_DOWN)
-    modifier |= GDK_CONTROL_MASK;
-  if (event_flag & ui::EF_ALT_DOWN)
-    modifier |= GDK_MOD1_MASK;
-  return static_cast<GdkModifierType>(modifier);
-}
-
-int EventFlagsFromGdkState(guint state) {
-  int flags = ui::EF_NONE;
-  flags |= (state & GDK_SHIFT_MASK) ? ui::EF_SHIFT_DOWN : ui::EF_NONE;
-  flags |= (state & GDK_LOCK_MASK) ? ui::EF_CAPS_LOCK_ON : ui::EF_NONE;
-  flags |= (state & GDK_CONTROL_MASK) ? ui::EF_CONTROL_DOWN : ui::EF_NONE;
-  flags |= (state & GDK_MOD1_MASK) ? ui::EF_ALT_DOWN : ui::EF_NONE;
-  flags |= (state & GDK_BUTTON1_MASK) ? ui::EF_LEFT_MOUSE_BUTTON : ui::EF_NONE;
-  flags |=
-      (state & GDK_BUTTON2_MASK) ? ui::EF_MIDDLE_MOUSE_BUTTON : ui::EF_NONE;
-  flags |= (state & GDK_BUTTON3_MASK) ? ui::EF_RIGHT_MOUSE_BUTTON : ui::EF_NONE;
-  return flags;
-}
-
-void TurnButtonBlue(GtkWidget* button) {
-  gtk_style_context_add_class(gtk_widget_get_style_context(button),
-                              "suggested-action");
-}
-
 void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) {
   if (!parent || !parent->GetHost())
     return;
@@ -260,14 +211,6 @@
 
 }  // namespace
 
-void* GetGdkSharedLibrary() {
-  std::string lib_name =
-      "libgdk-" + std::to_string(GTK_MAJOR_VERSION) + ".so.0";
-  static void* gdk_lib = dlopen(lib_name.c_str(), RTLD_LAZY);
-  DCHECK(gdk_lib);
-  return gdk_lib;
-}
-
 void* GetGtkSharedLibrary() {
   std::string lib_name =
       "libgtk-" + std::to_string(GTK_MAJOR_VERSION) + ".so.0";
@@ -662,14 +605,6 @@
   return prop_value;
 }
 
-#if defined(USE_X11)
-guint GetGdkKeyCodeForAccelerator(const ui::Accelerator& accelerator) {
-  // The second parameter is false because accelerator keys are expressed in
-  // terms of the non-shift-modified key.
-  return XKeysymForWindowsKeyCode(accelerator.key_code(), false);
-}
-#endif
-
 GdkDisplay* GetGdkDisplay() {
   GdkDisplay* display = nullptr;
   // TODO(crbug.com/1002674): Remove once GtkIM-based LinuxInputMethodContext
diff --git a/chrome/browser/ui/libgtkui/gtk_util.h b/chrome/browser/ui/libgtkui/gtk_util.h
index e0ab34ca..c9712cd 100644
--- a/chrome/browser/ui/libgtkui/gtk_util.h
+++ b/chrome/browser/ui/libgtkui/gtk_util.h
@@ -20,7 +20,6 @@
 
 namespace base {
 class CommandLine;
-class Environment;
 }
 
 namespace color_utils {
@@ -28,7 +27,6 @@
 }
 
 namespace ui {
-class Accelerator;
 class KeyEvent;
 }
 
@@ -38,18 +36,6 @@
 
 void GtkInitFromCommandLine(const base::CommandLine& command_line);
 
-// Returns the name of the ".desktop" file associated with our running process.
-std::string GetDesktopName(base::Environment* env);
-
-GdkModifierType GetGdkModifierForAccelerator(
-    const ui::Accelerator& accelerator);
-
-// Translates event flags into plaform independent event flags.
-int EventFlagsFromGdkState(guint state);
-
-// Style a GTK button as a BlueButton
-void TurnButtonBlue(GtkWidget* button);
-
 // Sets |dialog| as transient for |parent|, which will keep it on top and center
 // it above |parent|. Do nothing if |parent| is nullptr.
 void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent);
@@ -68,7 +54,6 @@
                        std::vector<views::FrameButton>* leading_buttons,
                        std::vector<views::FrameButton>* trailing_buttons);
 
-void* GetGdkSharedLibrary();
 void* GetGtkSharedLibrary();
 
 class CairoSurface {
@@ -189,11 +174,6 @@
 std::string GetGtkSettingsStringProperty(GtkSettings* settings,
                                          const gchar* prop_name);
 
-#if defined(USE_X11)
-// TODO(thomasanderson): Remove this once GtkStatusIcon is removed.
-guint GetGdkKeyCodeForAccelerator(const ui::Accelerator& accelerator);
-#endif
-
 // Get current GdkDisplay instance
 GdkDisplay* GetGdkDisplay();
 
diff --git a/chrome/browser/ui/libgtkui/libgtkui_export.h b/chrome/browser/ui/libgtkui/libgtkui_export.h
deleted file mode 100644
index 3fbae79..0000000
--- a/chrome/browser/ui/libgtkui/libgtkui_export.h
+++ /dev/null
@@ -1,28 +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 CHROME_BROWSER_UI_LIBGTKUI_LIBGTKUI_EXPORT_H_
-#define CHROME_BROWSER_UI_LIBGTKUI_LIBGTKUI_EXPORT_H_
-
-// Defines LIBGTKUI_EXPORT so that functionality implemented by our limited
-// gtk module can be exported to consumers.
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#error "LIBGTKUI does not build on Windows."
-
-#else  // defined(WIN32)
-#if defined(LIBGTKUI_IMPLEMENTATION)
-#define LIBGTKUI_EXPORT __attribute__((visibility("default")))
-#else
-#define LIBGTKUI_EXPORT
-#endif
-#endif
-
-#else  // defined(COMPONENT_BUILD)
-#define LIBGTKUI_EXPORT
-#endif
-
-#endif  // CHROME_BROWSER_UI_LIBGTKUI_LIBGTKUI_EXPORT_H_
diff --git a/chrome/browser/ui/libgtkui/native_theme_gtk.cc b/chrome/browser/ui/libgtkui/native_theme_gtk.cc
index b77b8a5..ad87f47 100644
--- a/chrome/browser/ui/libgtkui/native_theme_gtk.cc
+++ b/chrome/browser/ui/libgtkui/native_theme_gtk.cc
@@ -7,7 +7,6 @@
 #include <gtk/gtk.h>
 
 #include "chrome/browser/ui/libgtkui/gtk_util.h"
-#include "chrome/browser/ui/libgtkui/skia_utils_gtk.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/rect.h"
@@ -159,7 +158,8 @@
       GdkColor* color;
       gtk_style_context_get_style(link_context, "link-color", &color, nullptr);
       if (color) {
-        SkColor ret_color = GdkColorToSkColor(*color);
+        SkColor ret_color =
+            SkColorSetRGB(color->red >> 8, color->green >> 8, color->blue >> 8);
         // gdk_color_free() was deprecated in Gtk3.14.  This code path is only
         // taken on versions earlier than Gtk3.12, but the compiler doesn't know
         // that, so silence the deprecation warnings.
diff --git a/chrome/browser/ui/libgtkui/nav_button_provider_gtk.h b/chrome/browser/ui/libgtkui/nav_button_provider_gtk.h
index 175dc194..b878728a 100644
--- a/chrome/browser/ui/libgtkui/nav_button_provider_gtk.h
+++ b/chrome/browser/ui/libgtkui/nav_button_provider_gtk.h
@@ -7,15 +7,16 @@
 
 #include <map>
 
+#include "base/component_export.h"
 #include "chrome/browser/ui/frame_button_display_types.h"
-#include "chrome/browser/ui/libgtkui/libgtkui_export.h"
 #include "chrome/browser/ui/views/nav_button_provider.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/controls/button/button.h"
 
 namespace libgtkui {
 
-class LIBGTKUI_EXPORT NavButtonProviderGtk : public views::NavButtonProvider {
+class COMPONENT_EXPORT(LIBGTKUI) NavButtonProviderGtk
+    : public views::NavButtonProvider {
  public:
   NavButtonProviderGtk();
   ~NavButtonProviderGtk() override;
diff --git a/chrome/browser/ui/libgtkui/select_file_dialog_impl_kde.cc b/chrome/browser/ui/libgtkui/select_file_dialog_impl_kde.cc
index 949f15a7..a0a9335 100644
--- a/chrome/browser/ui/libgtkui/select_file_dialog_impl_kde.cc
+++ b/chrome/browser/ui/libgtkui/select_file_dialog_impl_kde.cc
@@ -31,7 +31,6 @@
 #include "ui/gfx/x/x11.h"
 #include "ui/strings/grit/ui_strings.h"
 
-
 using content::BrowserThread;
 
 namespace {
diff --git a/chrome/browser/ui/libgtkui/skia_utils_gtk.cc b/chrome/browser/ui/libgtkui/skia_utils_gtk.cc
deleted file mode 100644
index 6daec57..0000000
--- a/chrome/browser/ui/libgtkui/skia_utils_gtk.cc
+++ /dev/null
@@ -1,129 +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.
-
-#include "chrome/browser/ui/libgtkui/skia_utils_gtk.h"
-
-#include <gdk/gdk.h>
-
-#include "base/logging.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkUnPreMultiply.h"
-
-namespace libgtkui {
-
-// GDK_COLOR_RGB multiplies by 257 (= 0x10001) to distribute the bits evenly
-// See: http://www.mindcontrol.org/~hplus/graphics/expand-bits.html
-// To get back, we can just right shift by eight
-// (or, formulated differently, i == (i*257)/256 for all i < 256).
-
-#if !GTK_CHECK_VERSION(3, 90, 0)
-SkColor GdkColorToSkColor(GdkColor color) {
-  return SkColorSetRGB(color.red >> 8, color.green >> 8, color.blue >> 8);
-}
-
-GdkColor SkColorToGdkColor(SkColor color) {
-  GdkColor gdk_color = {
-      0, static_cast<guint16>(SkColorGetR(color) * kSkiaToGDKMultiplier),
-      static_cast<guint16>(SkColorGetG(color) * kSkiaToGDKMultiplier),
-      static_cast<guint16>(SkColorGetB(color) * kSkiaToGDKMultiplier)};
-  return gdk_color;
-}
-#endif
-
-const SkBitmap GdkPixbufToImageSkia(GdkPixbuf* pixbuf) {
-  // TODO(erg): What do we do in the case where the pixbuf fails these dchecks?
-  // I would prefer to use our gtk based canvas, but that would require
-  // recompiling half of our skia extensions with gtk support, which we can't
-  // do in this build.
-  DCHECK_EQ(GDK_COLORSPACE_RGB, gdk_pixbuf_get_colorspace(pixbuf));
-
-  int n_channels = gdk_pixbuf_get_n_channels(pixbuf);
-  int w = gdk_pixbuf_get_width(pixbuf);
-  int h = gdk_pixbuf_get_height(pixbuf);
-
-  SkBitmap ret;
-  ret.allocN32Pixels(w, h);
-  ret.eraseColor(0);
-
-  uint32_t* skia_data = static_cast<uint32_t*>(ret.getAddr(0, 0));
-
-  if (n_channels == 4) {
-    int total_length = w * h;
-    guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
-
-    // Now here's the trick: we need to convert the gdk data (which is RGBA and
-    // isn't premultiplied) to skia (which can be anything and premultiplied).
-    for (int i = 0; i < total_length; ++i, gdk_pixels += 4) {
-      const unsigned char& red = gdk_pixels[0];
-      const unsigned char& green = gdk_pixels[1];
-      const unsigned char& blue = gdk_pixels[2];
-      const unsigned char& alpha = gdk_pixels[3];
-
-      skia_data[i] = SkPreMultiplyARGB(alpha, red, green, blue);
-    }
-  } else if (n_channels == 3) {
-    // Because GDK makes rowstrides word aligned, we need to do something a bit
-    // more complex when a pixel isn't perfectly a word of memory.
-    int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
-    guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
-    for (int y = 0; y < h; ++y) {
-      int row = y * rowstride;
-
-      for (int x = 0; x < w; ++x) {
-        guchar* pixel = gdk_pixels + row + (x * 3);
-        const unsigned char& red = pixel[0];
-        const unsigned char& green = pixel[1];
-        const unsigned char& blue = pixel[2];
-
-        skia_data[y * w + x] = SkPreMultiplyARGB(255, red, green, blue);
-      }
-    }
-  } else {
-    NOTREACHED();
-  }
-
-  return ret;
-}
-
-GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap) {
-  if (bitmap.isNull())
-    return nullptr;
-
-  int width = bitmap.width();
-  int height = bitmap.height();
-
-  GdkPixbuf* pixbuf =
-      gdk_pixbuf_new(GDK_COLORSPACE_RGB,  // The only colorspace gtk supports.
-                     TRUE,                // There is an alpha channel.
-                     8, width, height);
-
-  // SkBitmaps are premultiplied, we need to unpremultiply them.
-  const int kBytesPerPixel = 4;
-  uint8_t* divided = gdk_pixbuf_get_pixels(pixbuf);
-
-  for (int y = 0, i = 0; y < height; y++) {
-    for (int x = 0; x < width; x++) {
-      uint32_t pixel = bitmap.getAddr32(0, y)[x];
-
-      int alpha = SkColorGetA(pixel);
-      if (alpha != 0 && alpha != 255) {
-        SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel);
-        divided[i + 0] = SkColorGetR(unmultiplied);
-        divided[i + 1] = SkColorGetG(unmultiplied);
-        divided[i + 2] = SkColorGetB(unmultiplied);
-        divided[i + 3] = alpha;
-      } else {
-        divided[i + 0] = SkColorGetR(pixel);
-        divided[i + 1] = SkColorGetG(pixel);
-        divided[i + 2] = SkColorGetB(pixel);
-        divided[i + 3] = alpha;
-      }
-      i += kBytesPerPixel;
-    }
-  }
-
-  return pixbuf;
-}
-
-}  // namespace libgtkui
diff --git a/chrome/browser/ui/libgtkui/skia_utils_gtk.h b/chrome/browser/ui/libgtkui/skia_utils_gtk.h
deleted file mode 100644
index bd6ed68a..0000000
--- a/chrome/browser/ui/libgtkui/skia_utils_gtk.h
+++ /dev/null
@@ -1,55 +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 CHROME_BROWSER_UI_LIBGTKUI_SKIA_UTILS_GTK_H_
-#define CHROME_BROWSER_UI_LIBGTKUI_SKIA_UTILS_GTK_H_
-
-#include <gtk/gtk.h>
-#include <stdint.h>
-
-#include "third_party/skia/include/core/SkColor.h"
-
-#if !GTK_CHECK_VERSION(3, 90, 0)
-typedef struct _GdkColor GdkColor;
-#endif
-typedef struct _GdkPixbuf GdkPixbuf;
-
-class SkBitmap;
-
-#if !GTK_CHECK_VERSION(3, 90, 0)
-// Define a macro for creating GdkColors from RGB values.  This is a macro to
-// allow static construction of literals, etc.  Use this like:
-//   GdkColor white = GDK_COLOR_RGB(0xff, 0xff, 0xff);
-#define GDK_COLOR_RGB(r, g, b)               \
-  {                                          \
-    0,                                       \
-    r * ::libgtkui::kSkiaToGDKMultiplier,    \
-    g * ::libgtkui::kSkiaToGDKMultiplier,    \
-    b * ::libgtkui::kSkiaToGDKMultiplier,    \
-  }
-#endif
-
-namespace libgtkui {
-
-#if !GTK_CHECK_VERSION(3, 90, 0)
-// Multiply uint8_t color components by this.
-const int kSkiaToGDKMultiplier = 257;
-
-// Converts GdkColors to the ARGB layout Skia expects.
-SkColor GdkColorToSkColor(GdkColor color);
-
-// Converts ARGB to GdkColor.
-GdkColor SkColorToGdkColor(SkColor color);
-#endif
-
-const SkBitmap GdkPixbufToImageSkia(GdkPixbuf* pixbuf);
-
-// Convert and copy a SkBitmap to a GdkPixbuf. NOTE: this uses BGRAToRGBA, so
-// it is an expensive operation.  The returned GdkPixbuf will have a refcount of
-// 1, and the caller is responsible for unrefing it when done.
-GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap);
-
-}  // namespace libgtkui
-
-#endif  // CHROME_BROWSER_UI_LIBGTKUI_SKIA_UTILS_GTK_H_
diff --git a/chrome/browser/ui/libgtkui/unity_service.h b/chrome/browser/ui/libgtkui/unity_service.h
deleted file mode 100644
index 8d67e146..0000000
--- a/chrome/browser/ui/libgtkui/unity_service.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_LIBGTKUI_UNITY_SERVICE_H_
-#define CHROME_BROWSER_UI_LIBGTKUI_UNITY_SERVICE_H_
-
-namespace unity {
-
-// Returns whether unity is currently running.
-bool IsRunning();
-
-// If unity is running, sets the download counter in the dock icon. Any value
-// other than 0 displays the badge.
-void SetDownloadCount(int count);
-
-// If unity is running, sets the download progress bar in the dock icon. Any
-// value between 0.0 and 1.0 (exclusive) shows the progress bar.
-void SetProgressFraction(float percentage);
-
-}  // namespace unity
-
-#endif  // CHROME_BROWSER_UI_LIBGTKUI_UNITY_SERVICE_H_
diff --git a/chrome/browser/ui/passwords/account_avatar_fetcher.cc b/chrome/browser/ui/passwords/account_avatar_fetcher.cc
index 9ddb45c..b840314 100644
--- a/chrome/browser/ui/passwords/account_avatar_fetcher.cc
+++ b/chrome/browser/ui/passwords/account_avatar_fetcher.cc
@@ -57,8 +57,7 @@
     network::mojom::URLLoaderFactory* loader_factory) {
   fetcher_.Init(std::string(), net::URLRequest::NEVER_CLEAR_REFERRER,
                 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
-                    net::LOAD_DO_NOT_SEND_AUTH_DATA |
-                    net::LOAD_MAYBE_USER_GESTURE);
+                    net::LOAD_DO_NOT_SEND_AUTH_DATA);
   fetcher_.Start(loader_factory);
 }
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 19b95890..ccc69ef 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/signin/signin_ui_util.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_handler.h"
 #include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -520,7 +521,7 @@
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   if (!browser)
     return;
-  browser->window()->ShowAvatarHighlightAnimation();
+  browser->window()->GetAutofillBubbleHandler()->OnPasswordSaved();
 }
 
 void ManagePasswordsUIController::NeverSavePasswordInternal() {
diff --git a/chrome/browser/ui/startup/bad_flags_prompt.cc b/chrome/browser/ui/startup/bad_flags_prompt.cc
index 433d18b..56444dd 100644
--- a/chrome/browser/ui/startup/bad_flags_prompt.cc
+++ b/chrome/browser/ui/startup/bad_flags_prompt.cc
@@ -144,7 +144,6 @@
 // "stability and security will suffer".
 static const base::Feature* kBadFeatureFlagsInAboutFlags[] = {
     &features::kAllowSignedHTTPExchangeCertsWithoutExtension,
-    &features::kBundledHTTPExchanges,
 #if defined(OS_ANDROID)
     &chrome::android::kCommandLineOnNonRooted,
 #endif  // OS_ANDROID
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 682f1e5..557a04c 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -15,10 +15,10 @@
 // https://crbug.com/967317
 const base::Feature kAnimatedAvatarButtonOnSignIn{
     "AnimatedAvatarButtonOnSignIn", base::FEATURE_ENABLED_BY_DEFAULT};
-// Enables an animated avatar button on the open-profile/startup trigger. This
+// Enables an animated avatar button on the open-window/startup trigger. This
 // feature is guarded by kAnimatedAvatarButton and serves as a kill-switch. See
 // https://crbug.com/967317
-const base::Feature kAnimatedAvatarButtonOnOpeningProfile{
+const base::Feature kAnimatedAvatarButtonOnOpeningWindow{
     "AnimatedAvatarButtonOnOpeningProfile", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables showing the EV certificate details in the Page Info bubble.
@@ -77,7 +77,7 @@
 // Enables a more prominent active tab title in dark mode to aid with
 // accessibility.
 const base::Feature kProminentDarkModeActiveTabTitle{
-    "ProminentDarkModeActiveTabTitle", base::FEATURE_ENABLED_BY_DEFAULT};
+    "ProminentDarkModeActiveTabTitle", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Enables a web-based separator that's only used for performance testing. See
 // https://crbug.com/993502.
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index f31445a..ee9f22a 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -19,7 +19,7 @@
 
 extern const base::Feature kAnimatedAvatarButton;
 extern const base::Feature kAnimatedAvatarButtonOnSignIn;
-extern const base::Feature kAnimatedAvatarButtonOnOpeningProfile;
+extern const base::Feature kAnimatedAvatarButtonOnOpeningWindow;
 
 extern const base::Feature kEvDetailsInPageInfo;
 
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
index f05e291d..aaf90a5 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -18,7 +18,6 @@
 #include "ash/public/cpp/window_properties.h"
 #include "ash/public/cpp/window_state_type.h"
 #include "ash/public/mojom/constants.mojom.h"
-#include "ash/wm/window_state.h"
 #include "base/bind.h"
 #include "base/logging.h"
 #include "chrome/browser/chromeos/note_taking_helper.h"
@@ -32,7 +31,6 @@
 #include "components/session_manager/core/session_manager.h"
 #include "extensions/common/constants.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/ui_base_types.h"
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h
index a1bff9d3..0e72bc7 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h
@@ -9,12 +9,14 @@
 #include <vector>
 
 #include "ash/public/cpp/tablet_mode_observer.h"
+#include "ash/wm/window_state.h"
 #include "ash/wm/window_state_observer.h"
 #include "base/gtest_prod_util.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
 #include "chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.h"
 #include "chrome/browser/ui/views/exclusive_access_bubble_views_context.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/views/context_menu_controller.h"
diff --git a/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc
new file mode 100644
index 0000000..fc2df452
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 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/views/autofill/autofill_bubble_handler_impl.h"
+
+#include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/autofill/payments/local_card_migration_bubble.h"
+#include "chrome/browser/ui/autofill/payments/save_card_bubble_view.h"
+#include "chrome/browser/ui/autofill/payments/save_card_ui.h"
+#include "chrome/browser/ui/views/autofill/payments/local_card_migration_bubble_views.h"
+#include "chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.h"
+#include "chrome/browser/ui/views/autofill/payments/save_card_bubble_views.h"
+#include "chrome/browser/ui/views/autofill/payments/save_card_failure_bubble_views.h"
+#include "chrome/browser/ui/views/autofill/payments/save_card_icon_view.h"
+#include "chrome/browser/ui/views/autofill/payments/save_card_manage_cards_bubble_views.h"
+#include "chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h"
+#include "chrome/browser/ui/views/autofill/payments/save_card_sign_in_promo_bubble_views.h"
+#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
+#include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
+#include "chrome/browser/ui/views/profiles/avatar_toolbar_button.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+
+namespace autofill {
+
+AutofillBubbleHandlerImpl::AutofillBubbleHandlerImpl(
+    ToolbarButtonProvider* toolbar_button_provider,
+    Profile* profile)
+    : toolbar_button_provider_(toolbar_button_provider) {
+  if (profile) {
+    personal_data_manager_observer_.Add(
+        PersonalDataManagerFactory::GetForProfile(
+            profile->GetOriginalProfile()));
+  }
+}
+
+AutofillBubbleHandlerImpl::~AutofillBubbleHandlerImpl() = default;
+
+// TODO(crbug.com/932818): Clean up this two functions and add helper for shared
+// code.
+SaveCardBubbleView* AutofillBubbleHandlerImpl::ShowSaveCreditCardBubble(
+    content::WebContents* web_contents,
+    SaveCardBubbleController* controller,
+    bool is_user_gesture) {
+  autofill::BubbleType bubble_type = controller->GetBubbleType();
+  PageActionIconView* icon_view =
+      toolbar_button_provider_->GetPageActionIconView(
+          PageActionIconType::kSaveCard);
+  views::View* anchor_view =
+      toolbar_button_provider_->GetAnchorView(PageActionIconType::kSaveCard);
+
+  autofill::SaveCardBubbleViews* bubble = nullptr;
+  switch (bubble_type) {
+    case autofill::BubbleType::LOCAL_SAVE:
+    case autofill::BubbleType::UPLOAD_SAVE:
+      bubble = new autofill::SaveCardOfferBubbleViews(anchor_view, web_contents,
+                                                      controller);
+      break;
+    case autofill::BubbleType::SIGN_IN_PROMO:
+      bubble = new autofill::SaveCardSignInPromoBubbleViews(
+          anchor_view, web_contents, controller);
+      break;
+    case autofill::BubbleType::MANAGE_CARDS:
+      bubble = new autofill::SaveCardManageCardsBubbleViews(
+          anchor_view, web_contents, controller);
+      break;
+    case autofill::BubbleType::FAILURE:
+      bubble = new autofill::SaveCardFailureBubbleViews(
+          anchor_view, web_contents, controller);
+      break;
+    case autofill::BubbleType::UPLOAD_IN_PROGRESS:
+    case autofill::BubbleType::INACTIVE:
+      break;
+  }
+  DCHECK(bubble);
+
+  if (icon_view)
+    bubble->SetHighlightedButton(icon_view);
+
+  views::BubbleDialogDelegateView::CreateBubble(bubble);
+  bubble->Show(is_user_gesture ? autofill::SaveCardBubbleViews::USER_GESTURE
+                               : autofill::SaveCardBubbleViews::AUTOMATIC);
+  return bubble;
+}
+
+LocalCardMigrationBubble*
+AutofillBubbleHandlerImpl::ShowLocalCardMigrationBubble(
+    content::WebContents* web_contents,
+    LocalCardMigrationBubbleController* controller,
+    bool is_user_gesture) {
+  autofill::LocalCardMigrationBubbleViews* bubble =
+      new autofill::LocalCardMigrationBubbleViews(
+          toolbar_button_provider_->GetAnchorView(
+              PageActionIconType::kLocalCardMigration),
+          web_contents, controller);
+
+  PageActionIconView* icon_view =
+      toolbar_button_provider_->GetPageActionIconView(
+          PageActionIconType::kLocalCardMigration);
+  if (icon_view)
+    bubble->SetHighlightedButton(icon_view);
+
+  views::BubbleDialogDelegateView::CreateBubble(bubble);
+  bubble->Show(is_user_gesture
+                   ? autofill::LocalCardMigrationBubbleViews::USER_GESTURE
+                   : autofill::LocalCardMigrationBubbleViews::AUTOMATIC);
+  return bubble;
+}
+
+void AutofillBubbleHandlerImpl::OnPasswordSaved() {
+  ShowAvatarHighlightAnimation();
+}
+
+void AutofillBubbleHandlerImpl::OnCreditCardSaved() {
+  ShowAvatarHighlightAnimation();
+}
+
+void AutofillBubbleHandlerImpl::ShowAvatarHighlightAnimation() {
+  AvatarToolbarButton* avatar =
+      toolbar_button_provider_->GetAvatarToolbarButton();
+  if (avatar)
+    avatar->ShowAvatarHighlightAnimation();
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h
new file mode 100644
index 0000000..179393bb
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h
@@ -0,0 +1,63 @@
+// Copyright (c) 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_VIEWS_AUTOFILL_AUTOFILL_BUBBLE_HANDLER_IMPL_H_
+#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_BUBBLE_HANDLER_IMPL_H_
+
+#include "base/macros.h"
+#include "base/scoped_observer.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_handler.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
+
+class Profile;
+class ToolbarButtonProvider;
+
+namespace content {
+class WebContents;
+}
+
+namespace autofill {
+class LocalCardMigrationBubble;
+class LocalCardMigrationBubbleController;
+class SaveCardBubbleView;
+class SaveCardBubbleController;
+
+class AutofillBubbleHandlerImpl : public AutofillBubbleHandler,
+                                  public PersonalDataManagerObserver {
+ public:
+  AutofillBubbleHandlerImpl(ToolbarButtonProvider* toolbar_button_provider,
+                            Profile* profile);
+  ~AutofillBubbleHandlerImpl() override;
+
+  // AutofillBubbleHandler:
+  SaveCardBubbleView* ShowSaveCreditCardBubble(
+      content::WebContents* web_contents,
+      SaveCardBubbleController* controller,
+      bool is_user_gesture) override;
+  LocalCardMigrationBubble* ShowLocalCardMigrationBubble(
+      content::WebContents* web_contents,
+      LocalCardMigrationBubbleController* controller,
+      bool is_user_gesture) override;
+  void OnPasswordSaved() override;
+
+  // autofill::PersonalDataManagerObserver:
+  void OnCreditCardSaved() override;
+
+ private:
+  // Executes highlight animation on toolbar's avatar icon.
+  void ShowAvatarHighlightAnimation();
+
+  ToolbarButtonProvider* toolbar_button_provider_ = nullptr;
+
+  ScopedObserver<autofill::PersonalDataManager,
+                 autofill::PersonalDataManagerObserver>
+      personal_data_manager_observer_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillBubbleHandlerImpl);
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_BUBBLE_HANDLER_IMPL_H_
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_view.cc
index 1c88c748..bad0a12 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view.cc
@@ -13,13 +13,16 @@
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/views/extensions/extensions_menu_item_view.h"
 #include "chrome/browser/ui/views/hover_button.h"
+#include "chrome/browser/ui/views/hover_button_controller.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/vector_icons/vector_icons.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/animation/ink_drop_host_view.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/image_button_factory.h"
+#include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/separator.h"
@@ -108,14 +111,29 @@
   AddChildView(std::move(scroll_view));
 
   AddChildView(std::make_unique<views::Separator>());
-  auto icon_view = CreateFixedSizeIconView();
-  icon_view->SetImage(
+
+  constexpr gfx::Insets kDefaultBorderInsets = gfx::Insets(12);
+  auto footer = std::make_unique<views::LabelButton>(
+      &button_listener_, l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSION),
+      views::style::CONTEXT_BUTTON);
+  footer->SetButtonController(std::make_unique<HoverButtonController>(
+      footer.get(), &button_listener_,
+      std::make_unique<views::Button::DefaultButtonControllerDelegate>(
+          footer.get())));
+  footer->SetImage(
+      views::Button::STATE_NORMAL,
       gfx::CreateVectorIcon(vector_icons::kSettingsIcon, 16,
                             GetNativeTheme()->GetSystemColor(
                                 ui::NativeTheme::kColorId_DefaultIconColor)));
-  auto footer = std::make_unique<HoverButton>(
-      &button_listener_, std::move(icon_view),
-      l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSION), base::string16());
+
+  // Items within a menu should not show focus rings.
+  footer->SetInstallFocusRingOnFocus(false);
+  footer->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
+  footer->SetBorder(views::CreateEmptyBorder(kDefaultBorderInsets));
+  footer->SetInkDropMode(views::InkDropHostView::InkDropMode::ON);
+  footer->set_ink_drop_base_color(HoverButton::GetInkDropColor(footer.get()));
+  footer->SetImageLabelSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric(
+      views::DISTANCE_BUTTON_HORIZONTAL_PADDING));
   footer->SetID(EXTENSIONS_SETTINGS_ID);
   manage_extensions_button_for_testing_ = footer.get();
   AddChildView(std::move(footer));
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index ef6caa3..7b2b1e4 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -51,7 +51,6 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
-#include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/layout.h"
 #include "ui/events/gestures/gesture_recognizer.h"
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
index 1b0243d..41f18ff 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
@@ -18,6 +18,7 @@
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/browser/ui/views/tab_icon_view_model.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 
 namespace {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index 52ba444..66cf2ef 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -11,13 +11,13 @@
 #include "ash/public/cpp/frame_header.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
 #include "ash/public/cpp/shelf_test_api.h"
+#include "ash/public/cpp/split_view_test_api.h"
 #include "ash/public/cpp/test/shell_test_api.h"
 #include "ash/public/cpp/window_pin_type.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/public/mojom/constants.mojom.h"
 #include "ash/shell.h"                                  // mash-ok
 #include "ash/wm/overview/overview_controller.h"        // mash-ok
-#include "ash/wm/splitview/split_view_controller.h"     // mash-ok
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"  // mash-ok
 #include "base/bind_helpers.h"
 #include "base/run_loop.h"
@@ -1280,8 +1280,8 @@
   EXPECT_FALSE(frame_view->caption_button_container_->GetVisible());
   EndOverview();
   EXPECT_FALSE(frame_view->caption_button_container_->GetVisible());
-  ash::Shell::Get()->split_view_controller()->SnapWindow(
-      widget->GetNativeWindow(), ash::SplitViewController::LEFT);
+  ash::SplitViewTestApi().SnapWindow(widget->GetNativeWindow(),
+                                     ash::SplitViewTestApi::SnapPosition::LEFT);
   EXPECT_FALSE(frame_view->caption_button_container_->GetVisible());
 }
 
@@ -1316,8 +1316,8 @@
   EndOverview();
   EXPECT_TRUE(frame_view2->caption_button_container_->GetVisible());
 
-  ash::Shell::Get()->split_view_controller()->SnapWindow(
-      widget2->GetNativeWindow(), ash::SplitViewController::RIGHT);
+  ash::SplitViewTestApi().SnapWindow(
+      widget2->GetNativeWindow(), ash::SplitViewTestApi::SnapPosition::RIGHT);
   EXPECT_TRUE(frame_view2->caption_button_container_->GetVisible());
 }
 
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 51a8648..24da581 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -70,14 +70,7 @@
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/accelerator_table.h"
 #include "chrome/browser/ui/views/accessibility/invert_bubble_view.h"
-#include "chrome/browser/ui/views/autofill/payments/local_card_migration_bubble_views.h"
-#include "chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.h"
-#include "chrome/browser/ui/views/autofill/payments/save_card_bubble_views.h"
-#include "chrome/browser/ui/views/autofill/payments/save_card_failure_bubble_views.h"
-#include "chrome/browser/ui/views/autofill/payments/save_card_icon_view.h"
-#include "chrome/browser/ui/views/autofill/payments/save_card_manage_cards_bubble_views.h"
-#include "chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h"
-#include "chrome/browser/ui/views/autofill/payments/save_card_sign_in_promo_bubble_views.h"
+#include "chrome/browser/ui/views/autofill/autofill_bubble_handler_impl.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h"
 #include "chrome/browser/ui/views/download/download_in_progress_dialog_view.h"
@@ -1026,6 +1019,10 @@
 
 void BrowserView::SetToolbarButtonProvider(ToolbarButtonProvider* provider) {
   toolbar_button_provider_ = provider;
+  // Recreate the autofill bubble handler when toolbar button provider changes.
+  autofill_bubble_handler_ =
+      std::make_unique<autofill::AutofillBubbleHandlerImpl>(
+          toolbar_button_provider_, browser_->profile());
 }
 
 bool BrowserView::UpdatePageActionIcon(PageActionIconType type) {
@@ -1034,11 +1031,8 @@
   return icon ? icon->Update() : false;
 }
 
-void BrowserView::ShowAvatarHighlightAnimation() {
-  AvatarToolbarButton* avatar_button = toolbar_->GetAvatarToolbarButton();
-  if (!avatar_button)
-    return;
-  avatar_button->ShowAvatarHighlightAnimation();
+autofill::AutofillBubbleHandler* BrowserView::GetAutofillBubbleHandler() {
+  return autofill_bubble_handler_.get();
 }
 
 void BrowserView::ExecutePageActionIconForTesting(PageActionIconType type) {
@@ -1309,56 +1303,6 @@
   return bubble;
 }
 
-// TODO(crbug.com/932818): Clean up this two functions and add helper for shared
-// code.
-// TODO(crbug.com/932818): Whether this function returns an owned pointer or not
-// is unclear. Sort that out, and make it return unique_ptr or not as
-// appropriate.
-autofill::SaveCardBubbleView* BrowserView::ShowSaveCreditCardBubble(
-    content::WebContents* web_contents,
-    autofill::SaveCardBubbleController* controller,
-    bool user_gesture) {
-  autofill::BubbleType bubble_type = controller->GetBubbleType();
-  PageActionIconView* icon_view =
-      toolbar_button_provider_->GetPageActionIconView(
-          PageActionIconType::kSaveCard);
-  views::View* anchor_view =
-      toolbar_button_provider_->GetAnchorView(PageActionIconType::kSaveCard);
-
-  autofill::SaveCardBubbleViews* bubble = nullptr;
-  switch (bubble_type) {
-    case autofill::BubbleType::LOCAL_SAVE:
-    case autofill::BubbleType::UPLOAD_SAVE:
-      bubble = new autofill::SaveCardOfferBubbleViews(anchor_view, web_contents,
-                                                      controller);
-      break;
-    case autofill::BubbleType::SIGN_IN_PROMO:
-      bubble = new autofill::SaveCardSignInPromoBubbleViews(
-          anchor_view, web_contents, controller);
-      break;
-    case autofill::BubbleType::MANAGE_CARDS:
-      bubble = new autofill::SaveCardManageCardsBubbleViews(
-          anchor_view, web_contents, controller);
-      break;
-    case autofill::BubbleType::FAILURE:
-      bubble = new autofill::SaveCardFailureBubbleViews(
-          anchor_view, web_contents, controller);
-      break;
-    case autofill::BubbleType::UPLOAD_IN_PROGRESS:
-    case autofill::BubbleType::INACTIVE:
-      break;
-  }
-  DCHECK(bubble);
-
-  if (icon_view)
-    bubble->SetHighlightedButton(icon_view);
-
-  views::BubbleDialogDelegateView::CreateBubble(bubble);
-  bubble->Show(user_gesture ? autofill::SaveCardBubbleViews::USER_GESTURE
-                            : autofill::SaveCardBubbleViews::AUTOMATIC);
-  return bubble;
-}
-
 SharingDialog* BrowserView::ShowSharingDialog(
     content::WebContents* web_contents,
     SharingUiController* controller) {
@@ -1396,29 +1340,6 @@
   return bubble;
 }
 
-autofill::LocalCardMigrationBubble* BrowserView::ShowLocalCardMigrationBubble(
-    content::WebContents* web_contents,
-    autofill::LocalCardMigrationBubbleController* controller,
-    bool user_gesture) {
-  autofill::LocalCardMigrationBubbleViews* bubble =
-      new autofill::LocalCardMigrationBubbleViews(
-          toolbar_button_provider_->GetAnchorView(
-              PageActionIconType::kLocalCardMigration),
-          web_contents, controller);
-
-  PageActionIconView* icon_view =
-      toolbar_button_provider_->GetPageActionIconView(
-          PageActionIconType::kLocalCardMigration);
-  if (icon_view)
-    bubble->SetHighlightedButton(icon_view);
-
-  views::BubbleDialogDelegateView::CreateBubble(bubble);
-  bubble->Show(user_gesture
-                   ? autofill::LocalCardMigrationBubbleViews::USER_GESTURE
-                   : autofill::LocalCardMigrationBubbleViews::AUTOMATIC);
-  return bubble;
-}
-
 ShowTranslateBubbleResult BrowserView::ShowTranslateBubble(
     content::WebContents* web_contents,
     translate::TranslateStep step,
@@ -2969,7 +2890,8 @@
     signin_metrics::AccessPoint access_point,
     bool focus_first_profile_button) {
   // Do not show avatar bubble if there is no avatar menu button.
-  views::Button* avatar_button = toolbar_->GetAvatarToolbarButton();
+  views::Button* avatar_button =
+      toolbar_button_provider_->GetAvatarToolbarButton();
   if (!avatar_button)
     return;
 
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index cd5e5337..596b244b 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -332,7 +332,7 @@
   bool IsFullscreen() const override;
   bool IsFullscreenBubbleVisible() const override;
   bool UpdatePageActionIcon(PageActionIconType type) override;
-  void ShowAvatarHighlightAnimation() override;
+  autofill::AutofillBubbleHandler* GetAutofillBubbleHandler() override;
   void ExecutePageActionIconForTesting(PageActionIconType type) override;
   LocationBar* GetLocationBar() const override;
   void SetFocusToLocationBar(bool select_all) override;
@@ -369,18 +369,10 @@
       content::WebContents* contents,
       qrcode_generator::QRCodeGeneratorBubbleController* controller,
       const GURL& url) override;
-  autofill::SaveCardBubbleView* ShowSaveCreditCardBubble(
-      content::WebContents* contents,
-      autofill::SaveCardBubbleController* controller,
-      bool is_user_gesture) override;
   send_tab_to_self::SendTabToSelfBubbleView* ShowSendTabToSelfBubble(
       content::WebContents* contents,
       send_tab_to_self::SendTabToSelfBubbleController* controller,
       bool is_user_gesture) override;
-  autofill::LocalCardMigrationBubble* ShowLocalCardMigrationBubble(
-      content::WebContents* contents,
-      autofill::LocalCardMigrationBubbleController* controller,
-      bool is_user_gesture) override;
   ShowTranslateBubbleResult ShowTranslateBubble(
       content::WebContents* contents,
       translate::TranslateStep step,
@@ -772,6 +764,9 @@
   // appear in a hosted app frame or in a tabbed UI toolbar.
   ToolbarButtonProvider* toolbar_button_provider_ = nullptr;
 
+  // The handler responsible for showing autofill bubbles.
+  std::unique_ptr<autofill::AutofillBubbleHandler> autofill_bubble_handler_;
+
   // Tracks and stores the last focused view which is not the
   // devtools_web_view_ or any of its children. Used to restore focus once
   // the devtools_web_view_ is hidden.
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
index 99742b03..3598090 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/window.h"
 #include "ui/aura/window_targeter.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/paint_context.h"
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
index a49aaebc..0950ed9 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
@@ -14,13 +14,10 @@
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_observer.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 #include "ui/gfx/geometry/rect.h"
 
-namespace aura {
-class Window;
-}
-
 class ImmersiveModeControllerAsh
     : public ImmersiveModeController,
       public ash::ImmersiveFullscreenControllerDelegate,
diff --git a/chrome/browser/ui/views/frame/toolbar_button_provider.h b/chrome/browser/ui/views/frame/toolbar_button_provider.h
index 415dc99..058ceb8 100644
--- a/chrome/browser/ui/views/frame/toolbar_button_provider.h
+++ b/chrome/browser/ui/views/frame/toolbar_button_provider.h
@@ -8,6 +8,7 @@
 #include "chrome/browser/ui/page_action/page_action_icon_type.h"
 
 class AppMenuButton;
+class AvatarToolbarButton;
 class BrowserActionsContainer;
 class PageActionIconView;
 class ToolbarActionView;
@@ -61,6 +62,9 @@
   // See comment in browser_window.h for more info.
   virtual void ZoomChangedForActiveTab(bool can_show_bubble) = 0;
 
+  // Returns the avatar button.
+  virtual AvatarToolbarButton* GetAvatarToolbarButton() = 0;
+
   // TODO(calamity): Move other buttons and button actions into here.
  protected:
   virtual ~ToolbarButtonProvider() {}
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 8461d34..092edef 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -101,7 +101,7 @@
   keyword_view_->OnMatchUpdate(this, match_);
 
   // Set up possible button.
-  if (match.ShouldShowButton()) {
+  if (match.ShouldShowTabMatchButton()) {
     suggestion_tab_switch_button_ = std::make_unique<OmniboxTabSwitchButton>(
         popup_contents_view_, this,
         l10n_util::GetStringUTF16(IDS_OMNIBOX_TAB_SUGGEST_HINT),
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index e7a59ba2..05b3b11 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -665,7 +665,7 @@
   // If we shift-tabbed (and actually moved) to a suggestion with a tab
   // switch button, select it.
   if (event.IsShiftDown() &&
-      model()->popup_model()->SelectedLineHasButton()) {
+      model()->popup_model()->SelectedLineHasTabMatch()) {
     model()->popup_model()->SetSelectedLineState(
         OmniboxPopupModel::BUTTON_FOCUSED);
     popup_view_->ProvideButtonFocusHint(
@@ -697,7 +697,7 @@
 
 bool OmniboxViewViews::SelectedSuggestionHasTabMatch() const {
   return model()->popup_model() &&  // Can be null in tests.
-         model()->popup_model()->SelectedLineHasButton();
+         model()->popup_model()->SelectedLineHasTabMatch();
 }
 
 bool OmniboxViewViews::DirectionAwareSelectionAtEnd() const {
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
index 12d4f78..d8bfa15 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
@@ -10,7 +10,6 @@
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/avatar_menu.h"
 #include "chrome/browser/profiles/profile.h"
@@ -170,9 +169,6 @@
   UpdateText();
 
   md_observer_.Add(ui::MaterialDesignController::GetInstance());
-  personal_data_manager_observer_.Add(
-      autofill::PersonalDataManagerFactory::GetForProfile(
-          profile_->GetOriginalProfile()));
 }
 
 AvatarToolbarButton::~AvatarToolbarButton() {
@@ -362,18 +358,19 @@
 
 void AvatarToolbarButton::OnUnconsentedPrimaryAccountChanged(
     const CoreAccountInfo& unconsented_primary_account_info) {
-  if (!base::FeatureList::IsEnabled(features::kAnimatedAvatarButtonOnSignIn))
-    return;
-  OnUserIdentityChanged(unconsented_primary_account_info);
+  OnUserIdentityChanged(unconsented_primary_account_info,
+                        features::kAnimatedAvatarButtonOnSignIn);
 }
 
 void AvatarToolbarButton::OnRefreshTokensLoaded() {
-  if (!signin_ui_util::ShouldShowIdentityOnOpeningProfile(
+  if (!signin_ui_util::ShouldShowAnimatedIdentityOnOpeningWindow(
           GetProfileAttributesStorage(), profile_)) {
     return;
   }
+
   OnUserIdentityChanged(IdentityManagerFactory::GetForProfile(profile_)
-                            ->GetUnconsentedPrimaryAccountInfo());
+                            ->GetUnconsentedPrimaryAccountInfo(),
+                        features::kAnimatedAvatarButtonOnOpeningWindow);
 }
 
 void AvatarToolbarButton::OnAccountsInCookieUpdated(
@@ -397,10 +394,6 @@
   PreferredSizeChanged();
 }
 
-void AvatarToolbarButton::OnCreditCardSaved() {
-  ShowAvatarHighlightAnimation();
-}
-
 void AvatarToolbarButton::ShowIdentityAnimation() {
   DCHECK_EQ(identity_animation_state_,
             IdentityAnimationState::kWaitingForImage);
@@ -574,9 +567,18 @@
 }
 
 void AvatarToolbarButton::OnUserIdentityChanged(
-    const CoreAccountInfo& user_identity) {
+    const CoreAccountInfo& user_identity,
+    const base::Feature& triggering_feature) {
+  if (user_identity.IsEmpty())
+    return;
+
+  // Record the last time the animated identity was set. This is done even if
+  // the feature is disabled, to allow comparing metrics between experimental
+  // groups.
+  signin_ui_util::RecordAnimatedIdentityTriggered(profile_);
+
   if (!base::FeatureList::IsEnabled(features::kAnimatedAvatarButton) ||
-      user_identity.IsEmpty()) {
+      !base::FeatureList::IsEnabled(triggering_feature)) {
     return;
   }
 
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button.h b/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
index 621e08e..b3cbf7e 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_PROFILES_AVATAR_TOOLBAR_BUTTON_H_
 #define CHROME_BROWSER_UI_VIEWS_PROFILES_AVATAR_TOOLBAR_BUTTON_H_
 
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "build/build_config.h"
@@ -14,8 +15,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/material_design/material_design_controller_observer.h"
@@ -28,8 +27,7 @@
                             public BrowserListObserver,
                             public ProfileAttributesStorage::Observer,
                             public signin::IdentityManager::Observer,
-                            public ui::MaterialDesignControllerObserver,
-                            public autofill::PersonalDataManagerObserver {
+                            public ui::MaterialDesignControllerObserver {
  public:
   explicit AvatarToolbarButton(Browser* browser);
   ~AvatarToolbarButton() override;
@@ -99,9 +97,6 @@
   // ui::MaterialDesignControllerObserver:
   void OnTouchUiChanged() override;
 
-  // autofill::PersonalDataManagerObserver:
-  void OnCreditCardSaved() override;
-
   void ShowIdentityAnimation();
   void HideIdentityAnimationWhenNotHoveredOrFocused();
   void HideIdentityAnimation();
@@ -119,7 +114,8 @@
   void SetInsets();
 
   // Initiates showing the identity |user_identity| (if non-empty).
-  void OnUserIdentityChanged(const CoreAccountInfo& user_identity);
+  void OnUserIdentityChanged(const CoreAccountInfo& user_identity,
+                             const base::Feature& triggering_feature);
 
   void ShowHighlightAnimation();
   void HideHighlightAnimation();
@@ -145,9 +141,6 @@
   ScopedObserver<ui::MaterialDesignController,
                  ui::MaterialDesignControllerObserver>
       md_observer_{this};
-  ScopedObserver<autofill::PersonalDataManager,
-                 autofill::PersonalDataManagerObserver>
-      personal_data_manager_observer_{this};
 
   base::WeakPtrFactory<AvatarToolbarButton> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
index f452966..8f831ea2 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
@@ -15,6 +15,7 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
+#include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
@@ -197,7 +198,7 @@
   if (IsShowing())
     return;
 
-  base::RecordAction(base::UserMetricsAction("ProfileMenu_Opened"));
+  signin_ui_util::RecordProfileMenuViewShown(browser->profile());
 
   ProfileMenuViewBase* bubble;
 
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index 3d5bb3d..360843d 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -190,7 +190,8 @@
 
   void OpenProfileMenuViews(Browser* browser) {
     BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
-    views::View* button = browser_view->toolbar()->GetAvatarToolbarButton();
+    views::View* button =
+        browser_view->toolbar_button_provider()->GetAvatarToolbarButton();
     DCHECK(button);
 
     ui::MouseEvent e(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
@@ -661,7 +662,7 @@
 
     // Click the avatar button to open the menu.
     views::View* avatar_button =
-        browser_view->toolbar()->GetAvatarToolbarButton();
+        browser_view->toolbar_button_provider()->GetAvatarToolbarButton();
     ASSERT_TRUE(avatar_button);
     Click(avatar_button);
 
diff --git a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
index f4d5787..60a3f16e 100644
--- a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
+++ b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
@@ -7,6 +7,7 @@
 #include "base/i18n/rtl.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/ui/views/accessibility/non_accessible_image_view.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "components/constrained_window/constrained_window_views.h"
@@ -20,9 +21,83 @@
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/border.h"
-#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
 
+using views::BoxLayout;
+
+namespace {
+
+// Fixed height of the illustration shown on the top of the dialog.
+constexpr int kSafeBrowsingIllustrationHeight = 120;
+
+// Fixed background color of the illustration shown on the top of the dialog in
+// normal mode.
+constexpr SkColor kSafeBrowsingPictureBackgroundColor =
+    SkColorSetARGB(0x0A, 0, 0, 0);
+
+// Fixed background color of the illustration shown on the top of the dialog in
+// dark mode.
+constexpr SkColor kSafeBrowsingPictureBackgroundColorDarkMode =
+    SkColorSetARGB(0x1A, 0x00, 0x00, 0x00);
+
+// Updates the image displayed on the illustration based on the current theme.
+void SafeBrowsingUpdateImageView(NonAccessibleImageView* image_view,
+                                 bool dark_mode_enabled) {
+  image_view->SetImage(gfx::CreateVectorIcon(
+      dark_mode_enabled ? kPasswordCheckWarningDarkIcon
+                        : kPasswordCheckWarningIcon,
+      dark_mode_enabled ? kSafeBrowsingPictureBackgroundColorDarkMode
+                        : kSafeBrowsingPictureBackgroundColor));
+}
+
+// Creates the illustration which is rendered on top of the dialog.
+std::unique_ptr<NonAccessibleImageView> SafeBrowsingCreateIllustration(
+    bool dark_mode_enabled) {
+  const gfx::Size illustration_size(
+      ChromeLayoutProvider::Get()->GetDistanceMetric(
+          DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH),
+      kSafeBrowsingIllustrationHeight);
+  auto image_view = std::make_unique<NonAccessibleImageView>();
+  image_view->SetPreferredSize(illustration_size);
+  SafeBrowsingUpdateImageView(image_view.get(), dark_mode_enabled);
+  image_view->SetSize(illustration_size);
+  image_view->SetVerticalAlignment(views::ImageView::Alignment::kLeading);
+  return image_view;
+}
+
+// Sets up the content containing the title and description for the dialog
+// rendered below the illustration.
+std::unique_ptr<views::View> SetupContent(const base::string16& title) {
+  auto content = std::make_unique<views::View>();
+  content->SetLayoutManager(std::make_unique<BoxLayout>(
+      BoxLayout::Orientation::kVertical, gfx::Insets(),
+      views::LayoutProvider::Get()->GetDistanceMetric(
+          views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
+  content->SetBorder(views::CreateEmptyBorder(
+      views::LayoutProvider::Get()->GetDialogInsetsForContentType(
+          views::CONTROL, views::CONTROL)));
+
+  auto title_label = std::make_unique<views::Label>(
+      title, views::style::CONTEXT_DIALOG_TITLE, views::style::STYLE_PRIMARY);
+  title_label->SetMultiLine(true);
+  title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  content->AddChildView(std::move(title_label));
+
+  return content;
+}
+
+// Creates the description on the modal warning dialog.
+views::Label* CreateMessageBodyLabel(base::string16 text) {
+  views::Label* message_body_label = new views::Label(text);
+  message_body_label->SetMultiLine(true);
+  message_body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  message_body_label->SetHandlesTooltips(false);
+  return message_body_label;
+}
+
+}  // namespace
+
 namespace safe_browsing {
 
 constexpr int kIconSize = 20;
@@ -52,18 +127,46 @@
   // |service| maybe NULL in tests.
   if (service_)
     service_->AddObserver(this);
+
+  views::Label* message_body_label = CreateMessageBodyLabel(
+      service_
+          ? service_->GetWarningDetailText(password_type)
+          : l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS));
+
+  if (password_type.account_type() ==
+      ReusedPasswordAccountType::SAVED_PASSWORD) {
+    CreateSavedPasswordReuseModalWarningDialog(message_body_label);
+  } else {
+    CreateGaiaPasswordReuseModalWarningDialog(message_body_label);
+  }
+}
+
+PasswordReuseModalWarningDialog::~PasswordReuseModalWarningDialog() {
+  if (service_)
+    service_->RemoveObserver(this);
+}
+
+void PasswordReuseModalWarningDialog::
+    CreateSavedPasswordReuseModalWarningDialog(
+        views::Label* message_body_label) {
+  SetLayoutManager(std::make_unique<BoxLayout>(
+      views::BoxLayout::Orientation::kVertical, gfx::Insets(),
+      0 /* between_child_spacing */));
+  std::unique_ptr<NonAccessibleImageView> illustration =
+      SafeBrowsingCreateIllustration(GetNativeTheme()->ShouldUseDarkColors());
+  std::unique_ptr<views::View> content = SetupContent(
+      l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHANGE_PASSWORD_SUMMARY));
+  content->AddChildView(std::move(message_body_label));
+  AddChildView(std::move(illustration));
+  AddChildView(std::move(content));
+}
+
+void PasswordReuseModalWarningDialog::CreateGaiaPasswordReuseModalWarningDialog(
+    views::Label* message_body_label) {
   const ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
   set_margins(
       provider->GetDialogInsetsForContentType(views::TEXT, views::TEXT));
   SetLayoutManager(std::make_unique<views::FillLayout>());
-
-  views::Label* message_body_label = new views::Label(
-      service_
-          ? service_->GetWarningDetailText(password_type)
-          : l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS));
-  message_body_label->SetMultiLine(true);
-  message_body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  message_body_label->SetHandlesTooltips(false);
   // Makes message label align with title label.
   int horizontal_adjustment =
       kIconSize +
@@ -78,11 +181,6 @@
   AddChildView(message_body_label);
 }
 
-PasswordReuseModalWarningDialog::~PasswordReuseModalWarningDialog() {
-  if (service_)
-    service_->RemoveObserver(this);
-}
-
 gfx::Size PasswordReuseModalWarningDialog::CalculatePreferredSize() const {
   constexpr int kDialogWidth = 400;
   return gfx::Size(kDialogWidth, GetHeightForWidth(kDialogWidth));
@@ -93,7 +191,12 @@
 }
 
 base::string16 PasswordReuseModalWarningDialog::GetWindowTitle() const {
-  return l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHANGE_PASSWORD_SUMMARY);
+  // It's ok to return an empty string for the title as this method
+  // is from views::DialogDelegateView class.
+  return password_type_.account_type() ==
+                 ReusedPasswordAccountType::SAVED_PASSWORD
+             ? base::string16()
+             : l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHANGE_PASSWORD_SUMMARY);
 }
 
 bool PasswordReuseModalWarningDialog::ShouldShowCloseButton() const {
@@ -101,20 +204,34 @@
 }
 
 gfx::ImageSkia PasswordReuseModalWarningDialog::GetWindowIcon() {
-  return gfx::CreateVectorIcon(kSecurityIcon, kIconSize, gfx::kChromeIconGrey);
+  return password_type_.account_type() ==
+                 ReusedPasswordAccountType::SAVED_PASSWORD
+             ? gfx::ImageSkia()
+             : gfx::CreateVectorIcon(kSecurityIcon, kIconSize,
+                                     gfx::kChromeIconGrey);
 }
 
 bool PasswordReuseModalWarningDialog::ShouldShowWindowIcon() const {
   return true;
 }
 
+int PasswordReuseModalWarningDialog::GetDialogButtons() const {
+  return password_type_.account_type() ==
+                 ReusedPasswordAccountType::SAVED_PASSWORD
+             ? ui::DIALOG_BUTTON_OK
+             : ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
+}
+
 bool PasswordReuseModalWarningDialog::Cancel() {
   std::move(done_callback_).Run(WarningAction::IGNORE_WARNING);
   return true;
 }
 
 bool PasswordReuseModalWarningDialog::Accept() {
-  std::move(done_callback_).Run(WarningAction::CHANGE_PASSWORD);
+  if (password_type_.account_type() !=
+      ReusedPasswordAccountType::SAVED_PASSWORD)
+    std::move(done_callback_).Run(WarningAction::CHANGE_PASSWORD);
+
   return true;
 }
 
@@ -128,11 +245,17 @@
     ui::DialogButton button) const {
   switch (button) {
     case ui::DIALOG_BUTTON_OK:
-      return l10n_util::GetStringUTF16(
-          password_type_.account_type() ==
-                  ReusedPasswordAccountType::NON_GAIA_ENTERPRISE
-              ? IDS_PAGE_INFO_CHANGE_PASSWORD_BUTTON
-              : IDS_PAGE_INFO_PROTECT_ACCOUNT_BUTTON);
+      switch (password_type_.account_type()) {
+        case ReusedPasswordAccountType::NON_GAIA_ENTERPRISE:
+          return l10n_util::GetStringUTF16(
+              IDS_PAGE_INFO_CHANGE_PASSWORD_BUTTON);
+        case ReusedPasswordAccountType::SAVED_PASSWORD:
+          return l10n_util::GetStringUTF16(
+              IDS_PAGE_INFO_DISMISS_PASSWORD_WARNING_BUTTON);
+        default:
+          return l10n_util::GetStringUTF16(
+              IDS_PAGE_INFO_PROTECT_ACCOUNT_BUTTON);
+      }
     case ui::DIALOG_BUTTON_CANCEL:
       return l10n_util::GetStringUTF16(
           IDS_PAGE_INFO_IGNORE_PASSWORD_WARNING_BUTTON);
diff --git a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h
index ee5c0fa..bc62347 100644
--- a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h
+++ b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.h
@@ -9,6 +9,7 @@
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "ui/views/controls/label.h"
 #include "ui/views/window/dialog_delegate.h"
 
 namespace content {
@@ -32,6 +33,11 @@
 
   ~PasswordReuseModalWarningDialog() override;
 
+  void CreateSavedPasswordReuseModalWarningDialog(
+      views::Label* message_body_label);
+  void CreateGaiaPasswordReuseModalWarningDialog(
+      views::Label* message_body_label);
+
   // views::DialogDelegateView:
   gfx::Size CalculatePreferredSize() const override;
   ui::ModalType GetModalType() const override;
@@ -39,6 +45,7 @@
   bool ShouldShowCloseButton() const override;
   gfx::ImageSkia GetWindowIcon() override;
   bool ShouldShowWindowIcon() const override;
+  int GetDialogButtons() const override;
   bool Cancel() override;
   bool Accept() override;
   bool Close() override;
diff --git a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
index 9c51558..2c0a4c5 100644
--- a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
+++ b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
@@ -175,6 +175,9 @@
 gfx::NativeViewId ScreenCaptureNotificationUIViews::OnStarted(
     base::OnceClosure stop_callback,
     content::MediaStreamUI::SourceCallback source_callback) {
+  if (GetWidget())
+    return 0;
+
   stop_callback_ = std::move(stop_callback);
   source_callback_ = std::move(source_callback);
 
@@ -225,11 +228,7 @@
   widget->SetOpacity(kWindowAlphaValue);
   widget->SetVisibleOnAllWorkspaces(true);
 
-#if defined(OS_WIN)
-  return gfx::NativeViewId(views::HWNDForWidget(widget));
-#else
   return 0;
-#endif
 }
 
 void ScreenCaptureNotificationUIViews::DeleteDelegate() {
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 76ed63d..474446a 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -1249,6 +1249,8 @@
   attached_context_tabs_closed_tracker_ =
       std::make_unique<DraggedTabsClosedTracker>(
           attached_context_->GetTabStripModel(), this);
+  if (attach_index_ != -1)
+    UpdateGroupForDraggedTabs();
 }
 
 void TabDragController::Detach(ReleaseCapture release_capture) {
@@ -2138,7 +2140,7 @@
   // ungrouped.
 
   const Tab* left_most_selected_tab =
-      source_context_->GetTabAt(selected.front());
+      attached_context_->GetTabAt(selected.front());
 
   const int buffer = left_most_selected_tab->width() / 4;
 
@@ -2152,7 +2154,7 @@
   // tab or there is a group header to the immediate left.
   int left_edge =
       attached_model->ContainsIndex(left_tab_index)
-          ? source_context_->GetTabAt(left_tab_index)->bounds().right() -
+          ? attached_context_->GetTabAt(left_tab_index)->bounds().right() -
                 tab_left_inset
           : tab_left_inset;
 
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 10d63138..c61e6e5 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -81,10 +81,10 @@
 #if defined(OS_CHROMEOS)
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
+#include "ash/public/cpp/split_view_test_api.h"
 #include "ash/public/cpp/test/shell_test_api.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
-#include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/window_state.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "chrome/browser/ui/views/frame/browser_view_layout.h"
@@ -1843,6 +1843,50 @@
   EXPECT_FALSE(browser2->window()->IsMaximized());
 }
 
+// Creates two browser with two tabs each. The first browser has one tab in a
+// group and the second tab not in a group. The second browser {browser2} has
+// two tabs in another group {group1}. Dragging the two tabs in the first
+// browser into the middle of the second browser will insert the two dragged
+// tabs into the {group1}} after the first tab.
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
+                       DragWindowIntoGroup) {
+  scoped_feature_list_.InitAndEnableFeature(features::kTabGroups);
+
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
+  TabStripModel* model = browser()->tab_strip_model();
+
+  AddTabsAndResetBrowser(browser(), 1);
+  model->AddToNewGroup({0});
+  StopAnimating(tab_strip);
+
+  // Set up the second browser with two tabs in a group with distinct IDs.
+  Browser* browser2 = CreateAnotherBrowserAndResize();
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStripModel* model2 = browser2->tab_strip_model();
+  AddTabsAndResetBrowser(browser2, 1);
+  ResetIDs(model2, 100);
+  TabGroupId group1 = model2->AddToNewGroup({0, 1});
+  StopAnimating(tab_strip2);
+
+  // Click the first tab and select the second tab so they are the only ones
+  // selected.
+  ASSERT_TRUE(PressInput(GetCenterInScreenCoordinates(tab_strip->tab_at(0))));
+  ASSERT_TRUE(ReleaseInput());
+  browser()->tab_strip_model()->ToggleSelectionAt(1);
+
+  // Move to the first tab and drag it enough so that it detaches, but not
+  // enough that it attaches to browser2.
+  DragTabAndNotify(tab_strip, base::BindOnce(&DragAllToSeparateWindowStep2,
+                                             this, tab_strip, tab_strip2));
+
+  // Release the mouse, stopping the drag session.
+  ASSERT_TRUE(ReleaseInput());
+
+  EXPECT_EQ("100 0 1 101", IDString(model2));
+  EXPECT_THAT(model2->ListTabsInGroup(group1),
+              testing::ElementsAre(0, 1, 2, 3));
+}
+
 namespace {
 
 // Invoked from the nested run loop.
@@ -2224,8 +2268,8 @@
 
   // Right snap the browser window.
   aura::Window* window = browser()->window()->GetNativeWindow();
-  ash::Shell::Get()->split_view_controller()->SnapWindow(
-      window, ash::SplitViewController::RIGHT);
+  ash::SplitViewTestApi().SnapWindow(
+      window, ash::SplitViewTestApi::SnapPosition::RIGHT);
   EXPECT_NE(gfx::Point(), window->GetBoundsInScreen().origin());
 
   DragWindowAndVerifyOffset(this, GetTabStripForBrowser(browser()), 0);
diff --git a/chrome/browser/ui/views/tabs/tab_group_underline.cc b/chrome/browser/ui/views/tabs/tab_group_underline.cc
index 5a91119..9f6340e 100644
--- a/chrome/browser/ui/views/tabs/tab_group_underline.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_underline.cc
@@ -34,12 +34,6 @@
   flags.setColor(GetColor());
   flags.setStyle(cc::PaintFlags::kFill_Style);
   canvas->DrawPath(path, flags);
-
-  // Ensure the active tab border stroke is repainted.
-  const int active_index = tab_strip_->controller()->GetActiveIndex();
-  if (active_index != ui::ListSelectionModel::kUnselectedIndex &&
-      tab_strip_->tab_at(active_index)->group() == group_)
-    tab_strip_->tab_at(active_index)->SchedulePaint();
 }
 
 void TabGroupUnderline::UpdateBounds() {
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 0ce5545..caf3eb5 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1158,6 +1158,9 @@
     // move in terms of model indices.
     layout_helper_->UpdateGroupHeaderIndex(new_group.value());
     group_underlines_[new_group.value()]->SchedulePaint();
+    const int active_index = controller_->GetActiveIndex();
+    if (active_index != ui::ListSelectionModel::kUnselectedIndex)
+      tab_at(active_index)->SchedulePaint();
   }
   if (old_group.has_value()) {
     if (controller_->ListTabsInGroup(old_group.value()).size() == 0) {
@@ -1175,6 +1178,9 @@
 void TabStrip::GroupVisualsChanged(TabGroupId group) {
   group_headers_[group]->VisualsChanged();
   group_underlines_[group]->SchedulePaint();
+  const int active_index = controller_->GetActiveIndex();
+  if (active_index != ui::ListSelectionModel::kUnselectedIndex)
+    tab_at(active_index)->SchedulePaint();
   // The group title may have changed size.
   UpdateIdealBounds();
   AnimateToIdealBounds();
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 308374a..3841c49d 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -465,18 +465,6 @@
                                  browser_->profile(), url, already_bookmarked);
 }
 
-AvatarToolbarButton* ToolbarView::GetAvatarToolbarButton() {
-  if (toolbar_account_icon_container_ &&
-      toolbar_account_icon_container_->avatar_button()) {
-    return toolbar_account_icon_container_->avatar_button();
-  }
-
-  if (avatar_)
-    return avatar_;
-
-  return nullptr;
-}
-
 ExtensionsToolbarButton* ToolbarView::GetExtensionsButton() const {
   return extensions_container_->extensions_button();
 }
@@ -863,6 +851,18 @@
       can_show_bubble);
 }
 
+AvatarToolbarButton* ToolbarView::GetAvatarToolbarButton() {
+  if (toolbar_account_icon_container_ &&
+      toolbar_account_icon_container_->avatar_button()) {
+    return toolbar_account_icon_container_->avatar_button();
+  }
+
+  if (avatar_)
+    return avatar_;
+
+  return nullptr;
+}
+
 BrowserRootView::DropIndex ToolbarView::GetDropIndex(
     const ui::DropTargetEvent& event) {
   return {browser_->tab_strip_model()->active_index(), false};
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h
index cf63d19eb..78cd8cb 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -128,9 +128,6 @@
                           bool already_bookmarked,
                           bookmarks::BookmarkBubbleObserver* observer);
 
-  // Access to the avatar button.
-  AvatarToolbarButton* GetAvatarToolbarButton();
-
   // Accessors.
   Browser* browser() const { return browser_; }
   BrowserActionsContainer* browser_actions() const { return browser_actions_; }
@@ -237,6 +234,7 @@
   views::AccessiblePaneView* GetAsAccessiblePaneView() override;
   views::View* GetAnchorView(PageActionIconType type) override;
   void ZoomChangedForActiveTab(bool can_show_bubble) override;
+  AvatarToolbarButton* GetAvatarToolbarButton() override;
 
   // BrowserRootView::DropTarget
   BrowserRootView::DropIndex GetDropIndex(
diff --git a/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc b/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc
index ebcf005..2d28475 100644
--- a/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc
@@ -455,6 +455,10 @@
   page_action_icon_container_view_->ZoomChangedForActiveTab(can_show_bubble);
 }
 
+AvatarToolbarButton* WebAppFrameToolbarView::GetAvatarToolbarButton() {
+  return nullptr;
+}
+
 void WebAppFrameToolbarView::OnWidgetVisibilityChanged(views::Widget* widget,
                                                        bool visibility) {
   if (!visibility || !pending_widget_visibility_)
diff --git a/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.h b/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.h
index 2d429be..dc6487a 100644
--- a/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.h
+++ b/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.h
@@ -25,6 +25,7 @@
 #include "ui/views/widget/widget_observer.h"
 
 class AppMenuButton;
+class AvatarToolbarButton;
 class BrowserView;
 class ExtensionsToolbarContainer;
 class PageActionIconContainerView;
@@ -118,6 +119,7 @@
   views::AccessiblePaneView* GetAsAccessiblePaneView() override;
   views::View* GetAnchorView(PageActionIconType type) override;
   void ZoomChangedForActiveTab(bool can_show_bubble) override;
+  AvatarToolbarButton* GetAvatarToolbarButton() override;
 
   // views::WidgetObserver:
   void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override;
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
index f6c8ec3b..7f6143e 100644
--- a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
+++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
@@ -92,13 +92,7 @@
     Profile* profile)
     : receiver_(this, std::move(receiver)),
       page_(std::move(page)),
-      profile_(profile)
-#if defined(OS_CHROMEOS)
-      ,
-      arc_app_list_prefs_observer_(this),
-      shelf_delegate_(this)
-#endif
-{
+      profile_(profile) {
   apps::AppServiceProxy* proxy =
       apps::AppServiceProxyFactory::GetForProfile(profile_);
 
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.h b/chrome/browser/ui/webui/app_management/app_management_page_handler.h
index 10fa404..6bc45d4 100644
--- a/chrome/browser/ui/webui/app_management/app_management_page_handler.h
+++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.h
@@ -22,12 +22,10 @@
 class Profile;
 
 class AppManagementPageHandler : public app_management::mojom::PageHandler,
-                                 public apps::AppRegistryCache::Observer
 #if defined(OS_CHROMEOS)
-    ,
-                                 public ArcAppListPrefs::Observer
+                                 public ArcAppListPrefs::Observer,
 #endif  // OS_CHROMEOS
-{
+                                 public apps::AppRegistryCache::Observer {
  public:
   AppManagementPageHandler(
       mojo::PendingReceiver<app_management::mojom::PageHandler> receiver,
@@ -79,9 +77,9 @@
   Profile* profile_;
 
 #if defined(OS_CHROMEOS)
-  ScopedObserver<ArcAppListPrefs, AppManagementPageHandler>
-      arc_app_list_prefs_observer_;
-  AppManagementShelfDelegate shelf_delegate_;
+  ScopedObserver<ArcAppListPrefs, ArcAppListPrefs::Observer>
+      arc_app_list_prefs_observer_{this};
+  AppManagementShelfDelegate shelf_delegate_{this};
 #endif  // OS_CHROMEOS
 
   DISALLOW_COPY_AND_ASSIGN(AppManagementPageHandler);
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.cc b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.cc
index 0b45e2d..04c52902 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.cc
@@ -18,7 +18,6 @@
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
-#include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/touchscreen_device.h"
 
 using content::BrowserThread;
@@ -42,7 +41,7 @@
 
 }  // namespace
 
-OobeDisplayChooser::OobeDisplayChooser() : scoped_observer_(this) {
+OobeDisplayChooser::OobeDisplayChooser() {
   // |connector| may be null in tests.
   auto* connector = content::GetSystemConnector();
   if (connector) {
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.h b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.h
index 555050c..c299372 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.h
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser.h
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
+#include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/input_device_event_observer.h"
 
 namespace ui {
@@ -44,7 +45,7 @@
   void OnDeviceListsComplete() override;
 
   ScopedObserver<ui::DeviceDataManager, ui::InputDeviceEventObserver>
-      scoped_observer_;
+      scoped_observer_{this};
   ash::mojom::CrosDisplayConfigControllerPtr cros_display_config_ptr_;
 
   base::WeakPtrFactory<OobeDisplayChooser> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 645cf9d..18b00d53 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -69,6 +69,8 @@
     {"close", IDS_CLOSE},
     {"clear", IDS_CLEAR},
     {"confirm", IDS_CONFIRM},
+    {"controlledSettingChildRestriction",
+     IDS_CONTROLLED_SETTING_CHILD_RESTRICTION},
     {"controlledSettingPolicy", IDS_CONTROLLED_SETTING_POLICY},
     {"done", IDS_DONE},
     {"learnMore", IDS_LEARN_MORE},
diff --git a/chrome/browser/ui/webui/omnibox/omnibox.mojom b/chrome/browser/ui/webui/omnibox/omnibox.mojom
index 7919093..e113fde 100644
--- a/chrome/browser/ui/webui/omnibox/omnibox.mojom
+++ b/chrome/browser/ui/webui/omnibox/omnibox.mojom
@@ -52,9 +52,10 @@
 };
 
 struct OmniboxResponse {
-  bool done;
+  int32 cursor_position;
   // Time delta since the request was started, in milliseconds.
   int32 time_since_omnibox_started_ms;
+  bool done;
   // The inferred metrics::OmniboxInputType of the request represented as a
   // string.
   string type;
diff --git a/chrome/browser/ui/webui/omnibox/omnibox_page_handler.cc b/chrome/browser/ui/webui/omnibox/omnibox_page_handler.cc
index c653eee..c8dc602 100644
--- a/chrome/browser/ui/webui/omnibox/omnibox_page_handler.cc
+++ b/chrome/browser/ui/webui/omnibox/omnibox_page_handler.cc
@@ -235,22 +235,25 @@
 }
 
 void OmniboxPageHandler::OnOmniboxQuery(AutocompleteController* controller,
-                                        const base::string16& input_text) {
+                                        const AutocompleteInput& input) {
+  time_omnibox_started_ = base::Time::Now();
+  input_ = input;
   page_->HandleNewAutocompleteQuery(controller == controller_.get(),
-                                    base::UTF16ToUTF8(input_text));
+                                    base::UTF16ToUTF8(input.text()));
 }
 
 void OmniboxPageHandler::OnOmniboxResultChanged(
     bool default_match_changed,
     AutocompleteController* controller) {
   mojom::OmniboxResponsePtr response(mojom::OmniboxResponse::New());
-  response->done = controller->done();
+  response->cursor_position = input_.cursor_position();
   response->time_since_omnibox_started_ms =
       (base::Time::Now() - time_omnibox_started_).InMilliseconds();
+  response->done = controller->done();
+  response->type = AutocompleteInput::TypeToString(input_.type());
   const base::string16 host =
       input_.text().substr(input_.parts().host.begin, input_.parts().host.len);
   response->host = base::UTF16ToUTF8(host);
-  response->type = AutocompleteInput::TypeToString(input_.type());
   bool is_typed_host;
   if (!LookupIsTypedHost(host, &is_typed_host))
     is_typed_host = false;
@@ -392,30 +395,22 @@
   // actual results to not depend on the state of the previous request.
   if (reset_autocomplete_controller)
     ResetController();
-  // TODO (manukh): OmniboxPageHandler::StartOmniboxQuery is invoked only for
-  // queries from the debug page and not for queries from the browser omnibox.
-  // time_omnibox_started_ and input_ are therefore not set for browser omnibox
-  // queries, resulting in inaccurate time_since_omnibox_started_ms, host, type,
-  // and is_typed_host values in the result object being sent to the debug page.
-  // For the user, this means the 'details' section is mostly inaccurate for
-  // browser omnibox queries.
-  time_omnibox_started_ = base::Time::Now();
-  input_ = AutocompleteInput(
+  AutocompleteInput input(
       base::UTF8ToUTF16(input_string), cursor_position,
       static_cast<metrics::OmniboxEventProto::PageClassification>(
           page_classification),
       ChromeAutocompleteSchemeClassifier(profile_));
   GURL current_url_gurl{current_url};
   if (current_url_gurl.is_valid())
-    input_.set_current_url(current_url_gurl);
-  input_.set_current_title(base::UTF8ToUTF16(current_url));
-  input_.set_prevent_inline_autocomplete(prevent_inline_autocomplete);
-  input_.set_prefer_keyword(prefer_keyword);
+    input.set_current_url(current_url_gurl);
+  input.set_current_title(base::UTF8ToUTF16(current_url));
+  input.set_prevent_inline_autocomplete(prevent_inline_autocomplete);
+  input.set_prefer_keyword(prefer_keyword);
   if (prefer_keyword)
-    input_.set_keyword_mode_entry_method(metrics::OmniboxEventProto::TAB);
-  input_.set_from_omnibox_focus(zero_suggest);
+    input.set_keyword_mode_entry_method(metrics::OmniboxEventProto::TAB);
+  input.set_from_omnibox_focus(zero_suggest);
 
-  OnOmniboxQuery(controller_.get(), input_.text());
+  OnOmniboxQuery(controller_.get(), input);
   controller_->Start(input_);
 }
 
diff --git a/chrome/browser/ui/webui/omnibox/omnibox_page_handler.h b/chrome/browser/ui/webui/omnibox/omnibox_page_handler.h
index 53f7831..c960ff0 100644
--- a/chrome/browser/ui/webui/omnibox/omnibox_page_handler.h
+++ b/chrome/browser/ui/webui/omnibox/omnibox_page_handler.h
@@ -43,7 +43,7 @@
 
   // OmniboxControllerEmitter::Observer overrides:
   void OnOmniboxQuery(AutocompleteController* controller,
-                      const base::string16& input_text) override;
+                      const AutocompleteInput& input) override;
   void OnOmniboxResultChanged(bool default_match_changed,
                               AutocompleteController* controller) override;
 
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 9f4c46a..446fc7d 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -1138,6 +1138,10 @@
 }
 
 void PrintPreviewHandler::OnPrintPreviewFailed(int request_id) {
+  WebContents* initiator = GetInitiator();
+  if (!initiator || initiator->IsBeingDestroyed())
+    return;  // Drop notification if fired during destruction sequence.
+
   std::string callback_id = GetCallbackId(request_id);
   if (callback_id.empty())
     return;
diff --git a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc
index 106c7bb..1c5b605 100644
--- a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.cc
@@ -85,9 +85,7 @@
 }  // namespace
 
 ChangePictureHandler::ChangePictureHandler()
-    : previous_image_index_(user_manager::User::USER_IMAGE_INVALID),
-      user_manager_observer_(this),
-      camera_observer_(this) {
+    : previous_image_index_(user_manager::User::USER_IMAGE_INVALID) {
   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
   audio::SoundsManager* manager = audio::SoundsManager::Get();
   manager->Initialize(SOUND_OBJECT_DELETE,
diff --git a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h
index 7003837..a3bb95d2 100644
--- a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h
@@ -139,9 +139,10 @@
   // Data for |user_photo_|.
   scoped_refptr<base::RefCountedBytes> user_photo_data_;
 
-  ScopedObserver<user_manager::UserManager, ChangePictureHandler>
-      user_manager_observer_;
-  ScopedObserver<CameraPresenceNotifier, ChangePictureHandler> camera_observer_;
+  ScopedObserver<user_manager::UserManager, user_manager::UserManager::Observer>
+      user_manager_observer_{this};
+  ScopedObserver<CameraPresenceNotifier, CameraPresenceNotifier::Observer>
+      camera_observer_{this};
 
   base::WeakPtrFactory<ChangePictureHandler> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc
index c38687e..ee16a53 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc
@@ -16,7 +16,6 @@
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/chromeos/events/event_rewriter_chromeos.h"
 #include "ui/chromeos/events/keyboard_layout_util.h"
-#include "ui/events/devices/device_data_manager.h"
 
 namespace {
 
@@ -59,8 +58,7 @@
   handler_->HandleInitialize(&args);
 }
 
-KeyboardHandler::KeyboardHandler() : observer_(this) {}
-
+KeyboardHandler::KeyboardHandler() = default;
 KeyboardHandler::~KeyboardHandler() = default;
 
 void KeyboardHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h
index 89e70bb..ee6c480 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h
@@ -8,16 +8,13 @@
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+#include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/input_device_event_observer.h"
 
 namespace base {
 class ListValue;
 }
 
-namespace ui {
-class DeviceDataManager;
-}
-
 namespace chromeos {
 namespace settings {
 
@@ -71,7 +68,8 @@
   // Sends the UI a message about whether hardware keyboard are attached.
   void UpdateKeyboards();
 
-  ScopedObserver<ui::DeviceDataManager, KeyboardHandler> observer_;
+  ScopedObserver<ui::DeviceDataManager, ui::InputDeviceEventObserver> observer_{
+      this};
 
   DISALLOW_COPY_AND_ASSIGN(KeyboardHandler);
 };
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc
index 79feea8..1906a33 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc
@@ -109,8 +109,7 @@
   handler_->HandleSetLidClosedBehavior(&args);
 }
 
-PowerHandler::PowerHandler(PrefService* prefs)
-    : prefs_(prefs), power_manager_client_observer_(this) {}
+PowerHandler::PowerHandler(PrefService* prefs) : prefs_(prefs) {}
 
 PowerHandler::~PowerHandler() {}
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h
index a362dcd..d55a394 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h
@@ -114,8 +114,8 @@
   // Used to watch power management prefs for changes so the UI can be notified.
   std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
 
-  ScopedObserver<PowerManagerClient, PowerHandler>
-      power_manager_client_observer_;
+  ScopedObserver<PowerManagerClient, PowerManagerClient::Observer>
+      power_manager_client_observer_{this};
 
   // Last lid state received from powerd.
   PowerManagerClient::LidState lid_state_ = PowerManagerClient::LidState::OPEN;
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc b/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc
index 202fcf8..ad7f2ee 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
-#include "ui/events/devices/device_data_manager.h"
 
 namespace chromeos {
 namespace settings {
@@ -29,8 +28,7 @@
 
 }  // namespace
 
-StylusHandler::StylusHandler() : note_observer_(this), input_observer_(this) {}
-
+StylusHandler::StylusHandler() = default;
 StylusHandler::~StylusHandler() = default;
 
 void StylusHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h b/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h
index a1be49b..c0e2429 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h
@@ -12,16 +12,13 @@
 #include "base/scoped_observer.h"
 #include "chrome/browser/chromeos/note_taking_helper.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+#include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/input_device_event_observer.h"
 
 namespace base {
 class ListValue;
 }
 
-namespace ui {
-class DeviceDataManager;
-}
-
 namespace chromeos {
 namespace settings {
 
@@ -63,9 +60,10 @@
   std::set<std::string> note_taking_app_ids_;
 
   // Observer registration.
-  ScopedObserver<NoteTakingHelper, NoteTakingHelper::Observer> note_observer_;
+  ScopedObserver<NoteTakingHelper, NoteTakingHelper::Observer> note_observer_{
+      this};
   ScopedObserver<ui::DeviceDataManager, ui::InputDeviceEventObserver>
-      input_observer_;
+      input_observer_{this};
 
   DISALLOW_COPY_AND_ASSIGN(StylusHandler);
 };
diff --git a/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.cc b/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.cc
index 3763dd4..601eeaf 100644
--- a/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.cc
@@ -20,7 +20,6 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/prefs/pref_service.h"
-#include "components/session_manager/core/session_manager.h"
 #include "content/public/browser/system_connector.h"
 #include "services/device/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -57,8 +56,7 @@
 
 }  // namespace
 
-FingerprintHandler::FingerprintHandler(Profile* profile)
-    : profile_(profile), session_observer_(this) {
+FingerprintHandler::FingerprintHandler(Profile* profile) : profile_(profile) {
   content::GetSystemConnector()->Connect(
       device::mojom::kServiceName, fp_service_.BindNewPipeAndPassReceiver());
   user_id_ = ProfileHelper::Get()->GetUserIdHashFromProfile(profile);
diff --git a/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.h b/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.h
index fbb4323d..97c85fd 100644
--- a/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/fingerprint_handler.h
@@ -8,6 +8,7 @@
 #include "base/containers/flat_map.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+#include "components/session_manager/core/session_manager.h"
 #include "components/session_manager/core/session_manager_observer.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -19,10 +20,6 @@
 class ListValue;
 }  // namespace base
 
-namespace session_manager {
-class SessionManager;
-}  // namespace session_manager
-
 namespace chromeos {
 namespace settings {
 
@@ -84,7 +81,7 @@
   mojo::Receiver<device::mojom::FingerprintObserver> receiver_{this};
   ScopedObserver<session_manager::SessionManager,
                  session_manager::SessionManagerObserver>
-      session_observer_;
+      session_observer_{this};
 
   base::WeakPtrFactory<FingerprintHandler> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
index 1990732..f249f72 100644
--- a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
@@ -21,9 +21,7 @@
 namespace chromeos {
 namespace settings {
 
-KerberosAccountsHandler::KerberosAccountsHandler()
-    : credentials_manager_observer_(this) {}
-
+KerberosAccountsHandler::KerberosAccountsHandler() = default;
 KerberosAccountsHandler::~KerberosAccountsHandler() = default;
 
 void KerberosAccountsHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.h b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.h
index 296cf45..00dfa0c 100644
--- a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.h
@@ -77,7 +77,7 @@
   // This class keeps track of that and removes this instance on destruction.
   ScopedObserver<KerberosCredentialsManager,
                  KerberosCredentialsManager::Observer>
-      credentials_manager_observer_;
+      credentials_manager_observer_{this};
 
   base::WeakPtrFactory<KerberosAccountsHandler> weak_factory_{this};
 
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index c3795a8..96511f3 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -447,6 +447,8 @@
      IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_POWERWASH},
     {"aboutRollbackInProgress", IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS},
     {"aboutRollbackSuccess", IDS_SETTINGS_UPGRADE_ROLLBACK_SUCCESS},
+    {"aboutUpdateOsSettingsLink",
+     IDS_SETTINGS_ABOUT_SEE_OS_SETTINGS_FOR_UPDATE_MESSAGE},
     {"aboutUpgradeUpdatingChannelSwitch",
      IDS_SETTINGS_UPGRADE_UPDATING_CHANNEL_SWITCH},
     {"aboutUpgradeSuccessChannelSwitch",
@@ -667,7 +669,6 @@
       {"policyAppUninstallPolicy", IDS_APP_MANAGEMENT_POLICY_APP_POLICY_STRING},
       {"size", IDS_APP_MANAGEMENT_SIZE},
       {"storage", IDS_APP_MANAGEMENT_STORAGE},
-      {"systemAppUninstallPolicy", IDS_APP_MANAGEMENT_SYSTEM_APP_POLICY_STRING},
       {"thisAppCan", IDS_APP_MANAGEMENT_THIS_APP_CAN},
       {"title", IDS_APP_MANAGEMENT_TITLE},
       {"uninstallApp", IDS_APP_MANAGEMENT_UNINSTALL_APP},
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler.cc b/chrome/browser/ui/webui/signin/inline_login_handler.cc
index fb483f45..5994aac2 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler.cc
@@ -162,11 +162,9 @@
       content::BrowserContext::GetStoragePartitionForSite(
           contents->GetBrowserContext(), signin::GetSigninPartitionURL());
 
-  net::CookieOptions cookie_options;
-  cookie_options.set_include_httponly();
-
   partition->GetCookieManagerForBrowserProcess()->GetCookieList(
-      GaiaUrls::GetInstance()->gaia_url(), cookie_options,
+      GaiaUrls::GetInstance()->gaia_url(),
+      net::CookieOptions::MakeAllInclusive(),
       base::BindOnce(&InlineLoginHandler::HandleCompleteLoginMessageWithCookies,
                      weak_ptr_factory_.GetWeakPtr(),
                      base::ListValue(args->GetList())));
diff --git a/chrome/browser/ui/webui/supervised_user_internals_message_handler.cc b/chrome/browser/ui/webui/supervised_user_internals_message_handler.cc
index 7f44dd8e..7d4027b 100644
--- a/chrome/browser/ui/webui/supervised_user_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/supervised_user_internals_message_handler.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/supervised_user/child_accounts/child_account_service.h"
 #include "chrome/browser/supervised_user/supervised_user_error_page/supervised_user_error_page.h"
-#include "chrome/browser/supervised_user/supervised_user_service.h"
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_settings_service.h"
 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
@@ -117,12 +116,11 @@
 
 }  // namespace
 
-SupervisedUserInternalsMessageHandler::SupervisedUserInternalsMessageHandler()
-    : scoped_observer_(this) {}
+SupervisedUserInternalsMessageHandler::SupervisedUserInternalsMessageHandler() =
+    default;
 
 SupervisedUserInternalsMessageHandler::
-    ~SupervisedUserInternalsMessageHandler() {
-}
+    ~SupervisedUserInternalsMessageHandler() = default;
 
 void SupervisedUserInternalsMessageHandler::RegisterMessages() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/chrome/browser/ui/webui/supervised_user_internals_message_handler.h b/chrome/browser/ui/webui/supervised_user_internals_message_handler.h
index f257eaa..619b580 100644
--- a/chrome/browser/ui/webui/supervised_user_internals_message_handler.h
+++ b/chrome/browser/ui/webui/supervised_user_internals_message_handler.h
@@ -10,6 +10,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/supervised_user/supervised_user_error_page/supervised_user_error_page.h"
+#include "chrome/browser/supervised_user/supervised_user_service.h"
 #include "chrome/browser/supervised_user/supervised_user_service_observer.h"
 #include "chrome/browser/supervised_user/supervised_user_url_filter.h"
 #include "content/public/browser/web_ui_message_handler.h"
@@ -18,8 +19,6 @@
 class ListValue;
 }  // namespace base
 
-class SupervisedUserService;
-
 // The implementation for the chrome://supervised-user-internals page.
 class SupervisedUserInternalsMessageHandler
     : public content::WebUIMessageHandler,
@@ -63,7 +62,7 @@
       user_settings_subscription_;
 
   ScopedObserver<SupervisedUserURLFilter, SupervisedUserURLFilter::Observer>
-      scoped_observer_;
+      scoped_observer_{this};
 
   base::WeakPtrFactory<SupervisedUserInternalsMessageHandler> weak_factory_{
       this};
diff --git a/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.cc b/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.cc
index 6c74dd9..262144c 100644
--- a/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.cc
+++ b/chrome/browser/ui/webui/tab_strip/thumbnail_tracker.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/thumbnails/thumbnail_image.h"
@@ -19,9 +20,7 @@
                                        public ThumbnailImage::Observer {
  public:
   ContentsData(ThumbnailTracker* parent, content::WebContents* contents)
-      : content::WebContentsObserver(contents),
-        parent_(parent),
-        observer_(this) {
+      : content::WebContentsObserver(contents), parent_(parent) {
     thumbnail_ = parent_->thumbnail_getter_.Run(contents);
     if (thumbnail_)
       observer_.Add(thumbnail_.get());
@@ -53,7 +52,9 @@
  private:
   ThumbnailTracker* parent_;
   scoped_refptr<ThumbnailImage> thumbnail_;
-  ScopedObserver<ThumbnailImage, ContentsData> observer_;
+  ScopedObserver<ThumbnailImage, ThumbnailImage::Observer> observer_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(ContentsData);
 };
 
 ThumbnailTracker::ThumbnailTracker(ThumbnailUpdatedCallback callback)
diff --git a/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java
index c8e1e71..f499f24 100644
--- a/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java
+++ b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java
@@ -16,8 +16,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import org.chromium.base.ContextUtils;
-
 /**
  * View-related utility methods.
  */
@@ -158,12 +156,13 @@
 
     /**
      * Creates a {@link RoundedBitmapDrawable} using the provided {@link Bitmap} and cornerRadius.
+     * @param resources The {@link Resources}.
      * @param icon The {@link Bitmap} to round.
      * @param cornerRadius The corner radius.
      * @return A {@link RoundedBitmapDrawable} for the provided {@link Bitmap}.
      */
-    public static RoundedBitmapDrawable createRoundedBitmapDrawable(Bitmap icon, int cornerRadius) {
-        Resources resources = ContextUtils.getApplicationContext().getResources();
+    public static RoundedBitmapDrawable createRoundedBitmapDrawable(
+            Resources resources, Bitmap icon, int cornerRadius) {
         RoundedBitmapDrawable roundedIcon = RoundedBitmapDrawableFactory.create(resources, icon);
         roundedIcon.setCornerRadius(cornerRadius);
         return roundedIcon;
diff --git a/chrome/browser/vr/service/browser_xr_runtime.cc b/chrome/browser/vr/service/browser_xr_runtime.cc
index 12bf6e8..a3c1889 100644
--- a/chrome/browser/vr/service/browser_xr_runtime.cc
+++ b/chrome/browser/vr/service/browser_xr_runtime.cc
@@ -444,6 +444,15 @@
   }
 }
 
+void BrowserXRRuntime::SetFramesThrottled(const VRServiceImpl* service,
+                                          bool throttled) {
+  if (service == presenting_service_) {
+    for (BrowserXRRuntimeObserver& observer : observers_) {
+      observer.SetFramesThrottled(throttled);
+    }
+  }
+}
+
 void BrowserXRRuntime::RequestSession(
     VRServiceImpl* service,
     const device::mojom::XRRuntimeSessionOptionsPtr& options,
diff --git a/chrome/browser/vr/service/browser_xr_runtime.h b/chrome/browser/vr/service/browser_xr_runtime.h
index 3751d44d..40988995 100644
--- a/chrome/browser/vr/service/browser_xr_runtime.h
+++ b/chrome/browser/vr/service/browser_xr_runtime.h
@@ -38,6 +38,8 @@
   // session. There can only be at most one active immersive session for the
   // XRRuntime. Set to null when there is no active immersive session.
   virtual void SetWebXRWebContents(content::WebContents* contents) = 0;
+
+  virtual void SetFramesThrottled(bool throttled) = 0;
 };
 
 // This class wraps a physical device's interfaces, and registers for events.
@@ -67,6 +69,7 @@
   void OnServiceAdded(VRServiceImpl* service);
   void OnServiceRemoved(VRServiceImpl* service);
   void ExitPresent(VRServiceImpl* service);
+  void SetFramesThrottled(const VRServiceImpl* service, bool throttled);
   void RequestSession(VRServiceImpl* service,
                       const device::mojom::XRRuntimeSessionOptionsPtr& options,
                       RequestSessionCallback callback);
diff --git a/chrome/browser/vr/service/isolated_device_provider.cc b/chrome/browser/vr/service/isolated_device_provider.cc
index b5f21325..5f44f633 100644
--- a/chrome/browser/vr/service/isolated_device_provider.cc
+++ b/chrome/browser/vr/service/isolated_device_provider.cc
@@ -77,7 +77,7 @@
     OnDevicesEnumerated();
   } else {
     device_provider_.reset();
-    binding_.Close();
+    receiver_.reset();
     retry_count_++;
     SetupDeviceProvider();
   }
@@ -98,16 +98,14 @@
 
 void IsolatedVRDeviceProvider::SetupDeviceProvider() {
   GetXRDeviceService()->BindRuntimeProvider(
-      mojo::MakeRequest(&device_provider_));
-  device_provider_.set_connection_error_handler(base::BindOnce(
+      device_provider_.BindNewPipeAndPassReceiver());
+  device_provider_.set_disconnect_handler(base::BindOnce(
       &IsolatedVRDeviceProvider::OnServerError, base::Unretained(this)));
 
-  device::mojom::IsolatedXRRuntimeProviderClientPtr client;
-  binding_.Bind(mojo::MakeRequest(&client));
-  device_provider_->RequestDevices(std::move(client));
+  device_provider_->RequestDevices(receiver_.BindNewPipeAndPassRemote());
 }
 
-IsolatedVRDeviceProvider::IsolatedVRDeviceProvider() : binding_(this) {}
+IsolatedVRDeviceProvider::IsolatedVRDeviceProvider() = default;
 
 IsolatedVRDeviceProvider::~IsolatedVRDeviceProvider() {
   for (auto& entry : ui_host_map_) {
diff --git a/chrome/browser/vr/service/isolated_device_provider.h b/chrome/browser/vr/service/isolated_device_provider.h
index 6182478d..ee81855 100644
--- a/chrome/browser/vr/service/isolated_device_provider.h
+++ b/chrome/browser/vr/service/isolated_device_provider.h
@@ -9,7 +9,8 @@
 #include "device/vr/public/mojom/isolated_xr_service.mojom.h"
 #include "device/vr/vr_device.h"
 #include "device/vr/vr_device_provider.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace vr {
 
@@ -48,7 +49,7 @@
 
   bool initialized_ = false;
   int retry_count_ = 0;
-  device::mojom::IsolatedXRRuntimeProviderPtr device_provider_;
+  mojo::Remote<device::mojom::IsolatedXRRuntimeProvider> device_provider_;
 
   base::RepeatingCallback<void(device::mojom::XRDeviceId,
                                device::mojom::VRDisplayInfoPtr,
@@ -57,7 +58,8 @@
   base::RepeatingCallback<void(device::mojom::XRDeviceId)>
       remove_device_callback_;
   base::OnceClosure initialization_complete_;
-  mojo::Binding<device::mojom::IsolatedXRRuntimeProviderClient> binding_;
+  mojo::Receiver<device::mojom::IsolatedXRRuntimeProviderClient> receiver_{
+      this};
 
   using UiHostMap =
       base::flat_map<device::mojom::XRDeviceId, std::unique_ptr<VRUiHost>>;
diff --git a/chrome/browser/vr/service/vr_service_impl.cc b/chrome/browser/vr/service/vr_service_impl.cc
index 6f74d32..f653c71d 100644
--- a/chrome/browser/vr/service/vr_service_impl.cc
+++ b/chrome/browser/vr/service/vr_service_impl.cc
@@ -542,6 +542,17 @@
     immersive_runtime->ExitPresent(this);
 }
 
+void VRServiceImpl::SetFramesThrottled(bool throttled) {
+  if (throttled != frames_throttled_) {
+    frames_throttled_ = throttled;
+    BrowserXRRuntime* immersive_runtime =
+        runtime_manager_->GetImmersiveRuntime();
+    if (immersive_runtime) {
+      immersive_runtime->SetFramesThrottled(this, frames_throttled_);
+    }
+  }
+}
+
 void VRServiceImpl::SetListeningForActivate(
     mojo::PendingRemote<device::mojom::VRDisplayClient> display_client) {
   // TODO(crbug.com/999745): Remove the check if the condition to check if
diff --git a/chrome/browser/vr/service/vr_service_impl.h b/chrome/browser/vr/service/vr_service_impl.h
index 535695c..f5a2237 100644
--- a/chrome/browser/vr/service/vr_service_impl.h
+++ b/chrome/browser/vr/service/vr_service_impl.h
@@ -65,6 +65,7 @@
       device::mojom::XRSessionOptionsPtr options,
       device::mojom::VRService::SupportsSessionCallback callback) override;
   void ExitPresent() override;
+  void SetFramesThrottled(bool throttled) override;
   // device::mojom::VRService WebVR compatibility functions
   void GetImmersiveVRDisplayInfo(
       device::mojom::VRService::GetImmersiveVRDisplayInfoCallback callback)
@@ -168,6 +169,7 @@
 
   bool initialization_complete_ = false;
   bool in_focused_frame_ = false;
+  bool frames_throttled_ = false;
 
   std::map<device::mojom::XRDeviceId, XrConsentPromptLevel>
       consent_granted_devices_;
diff --git a/chrome/browser/vr/ui_host/vr_ui_host_impl.cc b/chrome/browser/vr/ui_host/vr_ui_host_impl.cc
index 8af0b99a..0864736c 100644
--- a/chrome/browser/vr/ui_host/vr_ui_host_impl.cc
+++ b/chrome/browser/vr/ui_host/vr_ui_host_impl.cc
@@ -228,6 +228,7 @@
     StartUiRendering();
     InitCapturingStates();
     ui_rendering_thread_->SetWebXrPresenting(true);
+    ui_rendering_thread_->SetFramesThrottled(frames_throttled_);
 
     PollCapturingState();
 
@@ -257,6 +258,17 @@
   }
 }
 
+void VRUiHostImpl::SetFramesThrottled(bool throttled) {
+  frames_throttled_ = throttled;
+
+  if (!ui_rendering_thread_) {
+    DVLOG(1) << __func__ << ": no ui_rendering_thread_";
+    return;
+  }
+
+  ui_rendering_thread_->SetFramesThrottled(frames_throttled_);
+}
+
 void VRUiHostImpl::SetVRDisplayInfo(
     device::mojom::VRDisplayInfoPtr display_info) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/chrome/browser/vr/ui_host/vr_ui_host_impl.h b/chrome/browser/vr/ui_host/vr_ui_host_impl.h
index bf0f9eb5..4a00105 100644
--- a/chrome/browser/vr/ui_host/vr_ui_host_impl.h
+++ b/chrome/browser/vr/ui_host/vr_ui_host_impl.h
@@ -73,6 +73,7 @@
   // BrowserXRRuntimeObserver implementation.
   void SetWebXRWebContents(content::WebContents* contents) override;
   void SetVRDisplayInfo(device::mojom::VRDisplayInfoPtr display_info) override;
+  void SetFramesThrottled(bool throttled) override;
 
   // Internal methods used to start/stop the UI rendering thread that is used
   // for drawing browser UI (such as permission prompts) for display in VR.
@@ -120,6 +121,7 @@
   base::Time indicators_shown_start_time_;
   bool indicators_visible_ = false;
   bool indicators_showing_first_time_ = true;
+  bool frames_throttled_ = false;
 
   mojo::Remote<device::mojom::GeolocationConfig> geolocation_config_;
   base::CancelableClosure poll_capturing_state_task_;
diff --git a/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc b/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc
index a234cf5..27f147d 100644
--- a/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc
+++ b/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc
@@ -87,7 +87,7 @@
     return;
 
   if (presenting) {
-    compositor_->CreateImmersiveOverlay(mojo::MakeRequest(&overlay_));
+    compositor_->CreateImmersiveOverlay(overlay_.BindNewPipeAndPassReceiver());
     StartWebXrTimeout();
   } else {
     StopWebXrTimeout();
@@ -95,12 +95,15 @@
 }
 
 void VRBrowserRendererThreadWin::StartWebXrTimeout() {
-  waiting_for_first_frame_ = true;
+  frame_timeout_running_ = true;
   overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(),
                                          draw_state_.ShouldDrawWebXR());
 
-  overlay_->RequestNotificationOnWebXrSubmitted(base::BindOnce(
-      &VRBrowserRendererThreadWin::OnWebXRSubmitted, base::Unretained(this)));
+  if (!waiting_for_webxr_frame_) {
+    waiting_for_webxr_frame_ = true;
+    overlay_->RequestNotificationOnWebXrSubmitted(base::BindOnce(
+        &VRBrowserRendererThreadWin::OnWebXRSubmitted, base::Unretained(this)));
+  }
 
   webxr_spinner_timeout_closure_.Reset(base::BindOnce(
       &VRBrowserRendererThreadWin::OnWebXrTimeoutImminent,
@@ -124,7 +127,7 @@
   if (!webxr_frame_timeout_closure_.IsCancelled())
     webxr_frame_timeout_closure_.Cancel();
   OnSpinnerVisibilityChanged(false);
-  waiting_for_first_frame_ = false;
+  frame_timeout_running_ = false;
 }
 
 int VRBrowserRendererThreadWin::GetNextRequestId() {
@@ -144,16 +147,10 @@
   scheduler_ui_->OnWebXrTimedOut();
 }
 
-void VRBrowserRendererThreadWin::SetVisibleExternalPromptNotification(
-    ExternalPromptNotificationType prompt) {
-  if (!draw_state_.SetPrompt(prompt))
-    return;
-
+void VRBrowserRendererThreadWin::UpdateOverlayState() {
   if (draw_state_.ShouldDrawUI())
     StartOverlay();
 
-  ui_->SetVisibleExternalPromptNotification(prompt);
-
   if (overlay_)
     overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(),
                                            draw_state_.ShouldDrawWebXR());
@@ -167,26 +164,55 @@
   }
 }
 
-void VRBrowserRendererThreadWin::SetIndicatorsVisible(bool visible) {
-  if (!draw_state_.SetIndicatorsVisible(visible))
+void VRBrowserRendererThreadWin::SetFramesThrottled(bool throttled) {
+  if (frames_throttled_ == throttled)
     return;
 
-  if (draw_state_.ShouldDrawUI())
-    StartOverlay();
+  frames_throttled_ = throttled;
 
-  if (overlay_)
-    overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(),
-                                           draw_state_.ShouldDrawWebXR());
-  if (draw_state_.ShouldDrawUI()) {
-    if (overlay_)  // False only while testing
-      overlay_->RequestNextOverlayPose(
-          base::BindOnce(&VRBrowserRendererThreadWin::OnPose,
-                         base::Unretained(this), GetNextRequestId()));
+  if (g_frame_timeout_ui_disabled_for_testing_)
+    return;
+
+  if (frames_throttled_) {
+    StopWebXrTimeout();
+
+    // TODO(alcooper): This is not necessarily the best thing to show, but it's
+    // the best that we have right now.  It ensures that we submit *something*
+    // rather than letting the default system "Stalled" UI take over, without
+    // showing a message that the page is behaving badly.
+    OnWebXrTimeoutImminent();
   } else {
-    StopOverlay();
+    StartWebXrTimeout();
   }
 }
 
+void VRBrowserRendererThreadWin::SetVisibleExternalPromptNotification(
+    ExternalPromptNotificationType prompt) {
+  if (!draw_state_.SetPrompt(prompt))
+    return;
+
+  UpdateOverlayState();
+
+  if (!ui_) {
+    // If the ui is dismissed, make sure that we don't *actually* have a prompt
+    // state that we needed to set.
+    DCHECK(prompt == ExternalPromptNotificationType::kPromptNone);
+    return;
+  }
+
+  ui_->SetVisibleExternalPromptNotification(prompt);
+}
+
+void VRBrowserRendererThreadWin::SetIndicatorsVisible(bool visible) {
+  if (draw_state_.SetIndicatorsVisible(visible))
+    UpdateOverlayState();
+}
+
+void VRBrowserRendererThreadWin::OnSpinnerVisibilityChanged(bool visible) {
+  if (draw_state_.SetSpinnerVisible(visible))
+    UpdateOverlayState();
+}
+
 void VRBrowserRendererThreadWin::SetCapturingState(
     const CapturingStateModel& active_capturing,
     const CapturingStateModel& background_capturing,
@@ -313,31 +339,11 @@
   started_ = true;
 }
 
-void VRBrowserRendererThreadWin::OnSpinnerVisibilityChanged(bool visible) {
-  if (!draw_state_.SetSpinnerVisible(visible))
-    return;
-  if (draw_state_.ShouldDrawUI()) {
-    StartOverlay();
-  }
-
-  if (overlay_) {
-    overlay_->SetOverlayAndWebXRVisibility(draw_state_.ShouldDrawUI(),
-                                           draw_state_.ShouldDrawWebXR());
-  }
-
-  if (draw_state_.ShouldDrawUI()) {
-    if (overlay_)  // False only while testing.
-      overlay_->RequestNextOverlayPose(
-          base::BindOnce(&VRBrowserRendererThreadWin::OnPose,
-                         base::Unretained(this), GetNextRequestId()));
-  } else {
-    StopOverlay();
-  }
-}
-
 void VRBrowserRendererThreadWin::OnWebXRSubmitted() {
+  waiting_for_webxr_frame_ = false;
   if (scheduler_ui_)
     scheduler_ui_->OnWebXrFrameAvailable();
+
   StopWebXrTimeout();
 }
 
@@ -448,8 +454,12 @@
   if (!success && graphics_) {
     graphics_->ResetMemoryBuffer();
   }
-  if (scheduler_ui_ && success && !waiting_for_first_frame_)
+
+  // Make sure that we only notify that a WebXr frame is now
+  if (scheduler_ui_ && success && !frame_timeout_running_) {
     scheduler_ui_->OnWebXrFrameAvailable();
+  }
+
   if (draw_state_.ShouldDrawUI() && started_) {
     overlay_->RequestNextOverlayPose(
         base::BindOnce(&VRBrowserRendererThreadWin::OnPose,
diff --git a/chrome/browser/vr/win/vr_browser_renderer_thread_win.h b/chrome/browser/vr/win/vr_browser_renderer_thread_win.h
index ccf7465..981a7029 100644
--- a/chrome/browser/vr/win/vr_browser_renderer_thread_win.h
+++ b/chrome/browser/vr/win/vr_browser_renderer_thread_win.h
@@ -16,6 +16,7 @@
 #include "content/public/browser/web_contents.h"
 #include "device/vr/public/mojom/isolated_xr_service.mojom.h"
 #include "device/vr/public/mojom/vr_service.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace vr {
 
@@ -34,6 +35,7 @@
   void SetVRDisplayInfo(device::mojom::VRDisplayInfoPtr display_info);
   void SetLocationInfo(GURL gurl);
   void SetWebXrPresenting(bool presenting);
+  void SetFramesThrottled(bool throttled);
 
   // The below function(s) affect(s) whether UI is drawn or not.
   void SetVisibleExternalPromptNotification(
@@ -80,6 +82,8 @@
   void StopWebXrTimeout();
   int GetNextRequestId();
 
+  void UpdateOverlayState();
+
   // We need to do some initialization of GraphicsDelegateWin before
   // browser_renderer_, so we first store it in a unique_ptr, then transition
   // ownership to browser_renderer_.
@@ -102,10 +106,12 @@
   DrawState draw_state_;
   bool started_ = false;
   bool webxr_presenting_ = false;
-  bool waiting_for_first_frame_ = true;
+  bool frame_timeout_running_ = true;
+  bool waiting_for_webxr_frame_ = false;
+  bool frames_throttled_ = false;
   int current_request_id_ = 0;
 
-  device::mojom::ImmersiveOverlayPtr overlay_;
+  mojo::Remote<device::mojom::ImmersiveOverlay> overlay_;
   device::mojom::VRDisplayInfoPtr display_info_;
 
   base::CancelableOnceClosure webxr_frame_timeout_closure_;
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 87d0999c..3538802 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -43,8 +43,11 @@
     "web_app_registrar.h",
     "web_app_registry_update.cc",
     "web_app_registry_update.h",
+    "web_app_shortcut_manager.cc",
+    "web_app_shortcut_manager.h",
     "web_app_sync_bridge.cc",
     "web_app_sync_bridge.h",
+    "web_app_sync_install_delegate.h",
   ]
 
   deps = [
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 774f1c0..821b78f7 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -11,6 +11,8 @@
     "app_registrar_observer.h",
     "app_registry_controller.cc",
     "app_registry_controller.h",
+    "app_shortcut_manager.cc",
+    "app_shortcut_manager.h",
     "external_install_options.cc",
     "external_install_options.h",
     "externally_installed_web_app_prefs.cc",
diff --git a/chrome/browser/web_applications/components/app_shortcut_manager.cc b/chrome/browser/web_applications/components/app_shortcut_manager.cc
new file mode 100644
index 0000000..855ce52
--- /dev/null
+++ b/chrome/browser/web_applications/components/app_shortcut_manager.cc
@@ -0,0 +1,17 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/app_shortcut_manager.h"
+
+namespace web_app {
+
+AppShortcutManager::AppShortcutManager(Profile* profile) : profile_(profile) {}
+
+AppShortcutManager::~AppShortcutManager() = default;
+
+void AppShortcutManager::SetSubsystems(AppRegistrar* registrar) {
+  registrar_ = registrar;
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/app_shortcut_manager.h b/chrome/browser/web_applications/components/app_shortcut_manager.h
new file mode 100644
index 0000000..6229d7fa
--- /dev/null
+++ b/chrome/browser/web_applications/components/app_shortcut_manager.h
@@ -0,0 +1,40 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_APP_SHORTCUT_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_APP_SHORTCUT_MANAGER_H_
+
+#include "base/macros.h"
+
+class Profile;
+
+namespace web_app {
+
+class AppRegistrar;
+
+// TODO(crbug.com/860581): Migrate functions from
+// web_app_extension_shortcut.(h|cc) and
+// platform_apps/shortcut_manager.(h|cc) to the AppShortcutManager, so web app
+// shortcuts can be managed in an extensions agnostic way.
+class AppShortcutManager {
+ public:
+  explicit AppShortcutManager(Profile* profile);
+  virtual ~AppShortcutManager();
+
+  void SetSubsystems(AppRegistrar* registrar);
+
+ protected:
+  AppRegistrar* registrar() { return registrar_; }
+  Profile* profile() { return profile_; }
+
+ private:
+  AppRegistrar* registrar_ = nullptr;
+  Profile* const profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppShortcutManager);
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_APP_SHORTCUT_MANAGER_H_
diff --git a/chrome/browser/web_applications/components/web_app_constants.h b/chrome/browser/web_applications/components/web_app_constants.h
index 5a6b100..61d2419 100644
--- a/chrome/browser/web_applications/components/web_app_constants.h
+++ b/chrome/browser/web_applications/components/web_app_constants.h
@@ -19,6 +19,9 @@
   kSystem = kMinValue,
   kPolicy,
   kWebAppStore,
+  // We sync only regular user-installed apps from the open web. For
+  // user-installed apps without overlaps this is the only source that will be
+  // set.
   kSync,
   kDefault,
   kMaxValue
diff --git a/chrome/browser/web_applications/components/web_app_provider_base.h b/chrome/browser/web_applications/components/web_app_provider_base.h
index d61a7fc..3d8c7145 100644
--- a/chrome/browser/web_applications/components/web_app_provider_base.h
+++ b/chrome/browser/web_applications/components/web_app_provider_base.h
@@ -20,6 +20,7 @@
 class AppRegistryController;
 class FileHandlerManager;
 class AppIconManager;
+class AppShortcutManager;
 class WebAppPolicyManager;
 class ManifestUpdateManager;
 class WebAppAudioFocusIdMap;
@@ -58,6 +59,8 @@
   // Implements fetching of app icons.
   virtual AppIconManager& icon_manager() = 0;
 
+  virtual AppShortcutManager& shortcut_manager() = 0;
+
   DISALLOW_COPY_AND_ASSIGN(WebAppProviderBase);
 };
 
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn
index 9131703a..66999b4 100644
--- a/chrome/browser/web_applications/extensions/BUILD.gn
+++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -20,6 +20,8 @@
     "bookmark_app_registrar.h",
     "bookmark_app_registry_controller.cc",
     "bookmark_app_registry_controller.h",
+    "bookmark_app_shortcut_manager.cc",
+    "bookmark_app_shortcut_manager.h",
     "bookmark_app_util.cc",
     "bookmark_app_util.h",
     "web_app_extension_shortcut.cc",
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.cc b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.cc
new file mode 100644
index 0000000..13a18c9
--- /dev/null
+++ b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.cc
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.h"
+
+namespace extensions {
+
+BookmarkAppShortcutManager::BookmarkAppShortcutManager(Profile* profile)
+    : web_app::AppShortcutManager(profile) {}
+
+BookmarkAppShortcutManager::~BookmarkAppShortcutManager() = default;
+
+}  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.h b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.h
new file mode 100644
index 0000000..826a81c1
--- /dev/null
+++ b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.h
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_SHORTCUT_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_SHORTCUT_MANAGER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/web_applications/components/app_shortcut_manager.h"
+
+class Profile;
+
+namespace extensions {
+
+class BookmarkAppShortcutManager : public web_app::AppShortcutManager {
+ public:
+  explicit BookmarkAppShortcutManager(Profile* profile);
+  ~BookmarkAppShortcutManager() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BookmarkAppShortcutManager);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_SHORTCUT_MANAGER_H_
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
index 71fa5dd..74afac92 100644
--- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
+++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
@@ -255,13 +255,6 @@
   return reason == SHORTCUT_CREATION_BY_USER;
 }
 
-base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
-                                      const extensions::Extension& extension) {
-  return GetWebAppDataDirectory(
-      profile_path, extension.id(),
-      GURL(extensions::AppLaunchInfo::GetLaunchWebURL(&extension)));
-}
-
 void CreateShortcuts(ShortcutCreationReason reason,
                      const ShortcutLocations& locations,
                      Profile* profile,
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.h b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.h
index b00a8ba..a92e234 100644
--- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.h
+++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.h
@@ -54,11 +54,6 @@
                              Profile* profile,
                              const extensions::Extension* extension);
 
-// Gets the user data directory to use for |extension| located inside
-// |profile_path|.
-base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
-                                      const extensions::Extension& extension);
-
 // Creates shortcuts for an app. This loads the app's icon from disk, and calls
 // CreateShortcutsWithInfo(). If you already have a ShortcutInfo with the app's
 // icon loaded, you should use CreateShortcutsWithInfo() directly.
diff --git a/chrome/browser/web_applications/test/test_web_app_registry_controller.cc b/chrome/browser/web_applications/test/test_web_app_registry_controller.cc
index b2e3590..81060a4 100644
--- a/chrome/browser/web_applications/test/test_web_app_registry_controller.cc
+++ b/chrome/browser/web_applications/test/test_web_app_registry_controller.cc
@@ -7,6 +7,7 @@
 #include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/web_applications/test/test_web_app_database_factory.h"
+#include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_registry_update.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 
@@ -21,7 +22,7 @@
   mutable_registrar_ = std::make_unique<WebAppRegistrarMutable>(profile);
 
   sync_bridge_ = std::make_unique<WebAppSyncBridge>(
-      profile, database_factory_.get(), mutable_registrar_.get(),
+      profile, database_factory_.get(), mutable_registrar_.get(), this,
       mock_processor_.CreateForwardingProcessor());
 
   ON_CALL(processor(), IsTrackingMetadata())
@@ -51,6 +52,12 @@
     update->DeleteApp(app_id);
 }
 
+void TestWebAppRegistryController::InstallWebAppsAfterSync(
+    std::vector<WebApp*> web_apps) {}
+
+void TestWebAppRegistryController::UninstallWebAppsAfterSync(
+    std::vector<std::unique_ptr<WebApp>> web_apps) {}
+
 void TestWebAppRegistryController::DestroySubsystems() {
   mutable_registrar_.reset();
   sync_bridge_.reset();
diff --git a/chrome/browser/web_applications/test/test_web_app_registry_controller.h b/chrome/browser/web_applications/test/test_web_app_registry_controller.h
index 7d97770..322c473a 100644
--- a/chrome/browser/web_applications/test/test_web_app_registry_controller.h
+++ b/chrome/browser/web_applications/test/test_web_app_registry_controller.h
@@ -9,6 +9,7 @@
 
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
+#include "chrome/browser/web_applications/web_app_sync_install_delegate.h"
 #include "components/sync/model/mock_model_type_change_processor.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -20,7 +21,7 @@
 class WebAppSyncBridge;
 class WebApp;
 
-class TestWebAppRegistryController {
+class TestWebAppRegistryController : public SyncInstallDelegate {
  public:
   TestWebAppRegistryController();
   ~TestWebAppRegistryController();
@@ -35,6 +36,11 @@
   void UnregisterApp(const AppId& app_id);
   void UnregisterAll();
 
+  // SyncInstallDelegate:
+  void InstallWebAppsAfterSync(std::vector<WebApp*> web_apps) override;
+  void UninstallWebAppsAfterSync(
+      std::vector<std::unique_ptr<WebApp>> web_apps) override;
+
   void DestroySubsystems();
 
   TestWebAppDatabaseFactory& database_factory() { return *database_factory_; }
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h
index fa6888b..a2eeccb2 100644
--- a/chrome/browser/web_applications/web_app.h
+++ b/chrome/browser/web_applications/web_app.h
@@ -33,6 +33,9 @@
   const GURL& scope() const { return scope_; }
   const base::Optional<SkColor>& theme_color() const { return theme_color_; }
   blink::mojom::DisplayMode display_mode() const { return display_mode_; }
+  // Locally installed apps have shortcuts installed on various UI surfaces.
+  // If app isn't locally installed, it is excluded from UIs and only listed as
+  // a part of user's app library.
   bool is_locally_installed() const { return is_locally_installed_; }
   // Sync-initiated installation produces a sync placeholder app awaiting for
   // full installation process. The sync placeholder app has only app_id,
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc
index 87c6eb0..000f657 100644
--- a/chrome/browser/web_applications/web_app_database.cc
+++ b/chrome/browser/web_applications/web_app_database.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/web_applications/web_app_registry_update.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/model/metadata_batch.h"
+#include "components/sync/model/metadata_change_list.h"
 #include "components/sync/model/model_error.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
 
@@ -50,14 +51,18 @@
   write_batch_ = store_->CreateWriteBatch();
 }
 
-void WebAppDatabase::CommitTransaction(const RegistryUpdateData& update_data,
-                                       CompletionCallback callback) {
+void WebAppDatabase::CommitTransaction(
+    const RegistryUpdateData& update_data,
+    std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+    CompletionCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(opened_);
 
   DCHECK(write_batch_);
   DCHECK(!update_data.IsEmpty());
 
+  write_batch_->TakeMetadataChangesFrom(std::move(metadata_change_list));
+
   for (const std::unique_ptr<WebApp>& web_app : update_data.apps_to_create) {
     auto proto = CreateWebAppProto(*web_app);
     write_batch_->WriteData(web_app->app_id(), proto->SerializeAsString());
diff --git a/chrome/browser/web_applications/web_app_database.h b/chrome/browser/web_applications/web_app_database.h
index 4efe69e..07e7de7 100644
--- a/chrome/browser/web_applications/web_app_database.h
+++ b/chrome/browser/web_applications/web_app_database.h
@@ -21,6 +21,7 @@
 namespace syncer {
 class ModelError;
 class MetadataBatch;
+class MetadataChangeList;
 }  // namespace syncer
 
 namespace web_app {
@@ -49,8 +50,10 @@
   using CompletionCallback = base::OnceCallback<void(bool success)>;
   // There can be only 1 transaction at a time.
   void BeginTransaction();
-  void CommitTransaction(const RegistryUpdateData& update_data,
-                         CompletionCallback callback);
+  void CommitTransaction(
+      const RegistryUpdateData& update_data,
+      std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+      CompletionCallback callback);
   void CancelTransaction();
 
   // Exposed for testing.
diff --git a/chrome/browser/web_applications/web_app_install_manager.cc b/chrome/browser/web_applications/web_app_install_manager.cc
index a83e5ba..f0e2ff0 100644
--- a/chrome/browser/web_applications/web_app_install_manager.cc
+++ b/chrome/browser/web_applications/web_app_install_manager.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_data_retriever.h"
 #include "chrome/browser/web_applications/components/web_app_utils.h"
+#include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_install_task.h"
 #include "chrome/common/web_application_info.h"
 #include "content/public/browser/web_contents.h"
@@ -154,6 +155,18 @@
   web_contents_.reset();
 }
 
+void WebAppInstallManager::InstallWebAppsAfterSync(
+    std::vector<WebApp*> web_apps) {
+  // TODO(crbug.com/860583): Implement sync-initiated app installs.
+  NOTIMPLEMENTED();
+}
+
+void WebAppInstallManager::UninstallWebAppsAfterSync(
+    std::vector<std::unique_ptr<WebApp>> web_apps) {
+  // TODO(crbug.com/860583): Implement sync-initiated app uninstalls.
+  NOTIMPLEMENTED();
+}
+
 void WebAppInstallManager::SetUrlLoaderForTesting(
     std::unique_ptr<WebAppUrlLoader> url_loader) {
   url_loader_ = std::move(url_loader);
diff --git a/chrome/browser/web_applications/web_app_install_manager.h b/chrome/browser/web_applications/web_app_install_manager.h
index be3b2dc..4bf7aa2 100644
--- a/chrome/browser/web_applications/web_app_install_manager.h
+++ b/chrome/browser/web_applications/web_app_install_manager.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/web_applications/components/install_manager.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_url_loader.h"
+#include "chrome/browser/web_applications/web_app_sync_install_delegate.h"
 
 class Profile;
 
@@ -29,7 +30,8 @@
 class WebAppDataRetriever;
 class WebAppInstallTask;
 
-class WebAppInstallManager final : public InstallManager {
+class WebAppInstallManager final : public InstallManager,
+                                   public SyncInstallDelegate {
  public:
   explicit WebAppInstallManager(Profile* profile);
   ~WebAppInstallManager() override;
@@ -64,6 +66,11 @@
                                 OnceInstallCallback callback) override;
   void Shutdown() override;
 
+  // For the new USS-based system only. SyncInstallDelegate:
+  void InstallWebAppsAfterSync(std::vector<WebApp*> web_apps) override;
+  void UninstallWebAppsAfterSync(
+      std::vector<std::unique_ptr<WebApp>> web_apps) override;
+
   using DataRetrieverFactory =
       base::RepeatingCallback<std::unique_ptr<WebAppDataRetriever>()>;
   void SetDataRetrieverFactoryForTesting(
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 3ef1905e..c1dbccf8 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_registry_controller.h"
+#include "chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.h"
 #include "chrome/browser/web_applications/external_web_app_manager.h"
 #include "chrome/browser/web_applications/file_utils_wrapper.h"
 #include "chrome/browser/web_applications/pending_app_manager_impl.h"
@@ -32,6 +33,7 @@
 #include "chrome/browser/web_applications/web_app_install_manager.h"
 #include "chrome/browser/web_applications/web_app_provider_factory.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
+#include "chrome/browser/web_applications/web_app_shortcut_manager.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 #include "chrome/common/chrome_features.h"
 #include "components/pref_registry/pref_registry_syncable.h"
@@ -133,6 +135,11 @@
   return *icon_manager_;
 }
 
+AppShortcutManager& WebAppProvider::shortcut_manager() {
+  CheckIsConnected();
+  return *shortcut_manager_;
+}
+
 SystemWebAppManager& WebAppProvider::system_web_app_manager() {
   CheckIsConnected();
   return *system_web_app_manager_;
@@ -170,7 +177,8 @@
     auto mutable_registrar = std::make_unique<WebAppRegistrarMutable>(profile);
 
     sync_bridge = std::make_unique<WebAppSyncBridge>(
-        profile, database_factory_.get(), mutable_registrar.get());
+        profile, database_factory_.get(), mutable_registrar.get(),
+        install_manager_.get());
 
     // Upcast to read-only WebAppRegistrar.
     registrar = std::move(mutable_registrar);
@@ -181,6 +189,7 @@
   install_finalizer_ = std::make_unique<WebAppInstallFinalizer>(
       sync_bridge.get(), icon_manager.get());
   file_handler_manager_ = std::make_unique<WebAppFileHandlerManager>(profile);
+  shortcut_manager_ = std::make_unique<WebAppShortcutManager>(profile);
 
   // Upcast to unified subsystem types:
   registrar_ = std::move(registrar);
@@ -197,6 +206,8 @@
       std::make_unique<extensions::BookmarkAppInstallFinalizer>(profile);
   file_handler_manager_ =
       std::make_unique<extensions::BookmarkAppFileHandlerManager>(profile);
+  shortcut_manager_ =
+      std::make_unique<extensions::BookmarkAppShortcutManager>(profile);
 }
 
 void WebAppProvider::ConnectSubsystems() {
@@ -213,6 +224,7 @@
                                          registrar_.get(), ui_manager_.get());
   web_app_policy_manager_->SetSubsystems(pending_app_manager_.get());
   file_handler_manager_->SetSubsystems(registrar_.get());
+  shortcut_manager_->SetSubsystems(registrar_.get());
 
   connected_ = true;
 }
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h
index 99bc02a..fb651a21 100644
--- a/chrome/browser/web_applications/web_app_provider.h
+++ b/chrome/browser/web_applications/web_app_provider.h
@@ -31,6 +31,7 @@
 // Forward declarations of generalized interfaces.
 class AppRegistryController;
 class AppIconManager;
+class AppShortcutManager;
 class ExternalWebAppManager;
 class FileHandlerManager;
 class InstallFinalizer;
@@ -77,6 +78,7 @@
   WebAppAudioFocusIdMap& audio_focus_id_map() override;
   FileHandlerManager& file_handler_manager() override;
   AppIconManager& icon_manager() override;
+  AppShortcutManager& shortcut_manager() override;
 
   SystemWebAppManager& system_web_app_manager();
 
@@ -121,6 +123,7 @@
   std::unique_ptr<InstallFinalizer> install_finalizer_;
   std::unique_ptr<ManifestUpdateManager> manifest_update_manager_;
   std::unique_ptr<PendingAppManager> pending_app_manager_;
+  std::unique_ptr<AppShortcutManager> shortcut_manager_;
   std::unique_ptr<SystemWebAppManager> system_web_app_manager_;
   std::unique_ptr<WebAppAudioFocusIdMap> audio_focus_id_map_;
   std::unique_ptr<WebAppInstallManager> install_manager_;
diff --git a/chrome/browser/web_applications/web_app_shortcut_manager.cc b/chrome/browser/web_applications/web_app_shortcut_manager.cc
new file mode 100644
index 0000000..f0dd30f
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_shortcut_manager.cc
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/web_app_shortcut_manager.h"
+
+namespace web_app {
+
+WebAppShortcutManager::WebAppShortcutManager(Profile* profile)
+    : AppShortcutManager(profile) {}
+
+WebAppShortcutManager::~WebAppShortcutManager() = default;
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_shortcut_manager.h b/chrome/browser/web_applications/web_app_shortcut_manager.h
new file mode 100644
index 0000000..27b2983
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_shortcut_manager.h
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SHORTCUT_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SHORTCUT_MANAGER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/web_applications/components/app_shortcut_manager.h"
+
+class Profile;
+
+namespace web_app {
+
+class WebAppShortcutManager : public AppShortcutManager {
+ public:
+  explicit WebAppShortcutManager(Profile* profile);
+  ~WebAppShortcutManager() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebAppShortcutManager);
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SHORTCUT_MANAGER_H_
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.cc b/chrome/browser/web_applications/web_app_sync_bridge.cc
index 5c3c246..4a4a7eb 100644
--- a/chrome/browser/web_applications/web_app_sync_bridge.cc
+++ b/chrome/browser/web_applications/web_app_sync_bridge.cc
@@ -5,16 +5,20 @@
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 
 #include <memory>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/containers/flat_set.h"
 #include "base/logging.h"
 #include "base/optional.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_database.h"
 #include "chrome/browser/web_applications/web_app_database_factory.h"
 #include "chrome/browser/web_applications/web_app_registry_update.h"
+#include "chrome/browser/web_applications/web_app_sync_install_delegate.h"
 #include "chrome/common/channel_info.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/report_unrecoverable_error.h"
@@ -36,27 +40,71 @@
   auto entity_data = std::make_unique<syncer::EntityData>();
   entity_data->name = app.name();
 
-  sync_pb::WebAppSpecifics* specifics =
+  sync_pb::WebAppSpecifics* sync_data =
       entity_data->specifics.mutable_web_app();
-  specifics->set_launch_url(app.launch_url().spec());
-  specifics->set_name(app.name());
-  specifics->set_display_mode(ToWebAppSpecificsDisplayMode(app.display_mode()));
-  if (app.theme_color().has_value())
-    specifics->set_theme_color(app.theme_color().value());
+  sync_data->set_launch_url(app.launch_url().spec());
+  sync_data->set_display_mode(ToWebAppSpecificsDisplayMode(app.display_mode()));
+  sync_data->set_name(app.sync_data().name);
+  if (app.sync_data().theme_color.has_value())
+    sync_data->set_theme_color(app.sync_data().theme_color.value());
 
   return entity_data;
 }
 
+void ApplySyncDataToApp(const sync_pb::WebAppSpecifics& sync_data,
+                        WebApp* app) {
+  app->AddSource(Source::kSync);
+
+  // app_id is a hash of launch_url. Parse launch_url first:
+  GURL launch_url(sync_data.launch_url());
+  if (launch_url.is_empty() || !launch_url.is_valid()) {
+    DLOG(ERROR) << "ApplySyncDataToApp: launch_url parse error.";
+    return;
+  }
+  if (app->app_id() != GenerateAppIdFromURL(launch_url)) {
+    DLOG(ERROR) << "ApplySyncDataToApp: app_id doesn't match launch_url.";
+    return;
+  }
+
+  if (app->launch_url().is_empty()) {
+    app->SetLaunchUrl(std::move(launch_url));
+  } else if (app->launch_url() != launch_url) {
+    DLOG(ERROR)
+        << "ApplySyncDataToApp: existing launch_url doesn't match launch_url.";
+    return;
+  }
+
+  // Always override display mode with a synced value.
+  app->SetDisplayMode(ToMojomDisplayMode(sync_data.display_mode()));
+
+  WebApp::SyncData parsed_sync_data;
+  parsed_sync_data.name = sync_data.name();
+  if (sync_data.has_theme_color())
+    parsed_sync_data.theme_color = sync_data.theme_color();
+  app->SetSyncData(parsed_sync_data);
+}
+
+bool AreAppsLocallyInstalledByDefault() {
+#if defined(OS_CHROMEOS)
+  // On Chrome OS, sync always locally installs an app.
+  return true;
+#else
+  return false;
+#endif
+}
+
 }  // namespace
 
 WebAppSyncBridge::WebAppSyncBridge(
     Profile* profile,
     AbstractWebAppDatabaseFactory* database_factory,
-    WebAppRegistrarMutable* registrar)
+    WebAppRegistrarMutable* registrar,
+    SyncInstallDelegate* install_delegate)
     : WebAppSyncBridge(
           profile,
           database_factory,
           registrar,
+          install_delegate,
           std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
               syncer::WEB_APPS,
               base::BindRepeating(&syncer::ReportUnrecoverableError,
@@ -66,10 +114,12 @@
     Profile* profile,
     AbstractWebAppDatabaseFactory* database_factory,
     WebAppRegistrarMutable* registrar,
+    SyncInstallDelegate* install_delegate,
     std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor)
     : AppRegistryController(profile),
       syncer::ModelTypeSyncBridge(std::move(change_processor)),
-      registrar_(registrar) {
+      registrar_(registrar),
+      install_delegate_(install_delegate) {
   DCHECK(database_factory);
   DCHECK(registrar_);
   database_ = std::make_unique<WebAppDatabase>(
@@ -103,12 +153,14 @@
 
   CheckRegistryUpdateData(update->update_data());
 
-  registrar_->CountMutation();
-
   std::unique_ptr<RegistryUpdateData> update_data = update->TakeUpdateData();
+  std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
+      CreateMetadataChangeList();
+
+  UpdateSync(*update_data, metadata_change_list.get());
 
   database_->CommitTransaction(
-      *update_data,
+      *update_data, std::move(metadata_change_list),
       base::BindOnce(&WebAppSyncBridge::OnDataWritten,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 
@@ -157,19 +209,73 @@
 #endif
 }
 
-void WebAppSyncBridge::UpdateRegistrar(
+std::vector<std::unique_ptr<WebApp>> WebAppSyncBridge::UpdateRegistrar(
     std::unique_ptr<RegistryUpdateData> update_data) {
+  registrar_->CountMutation();
+
+  std::vector<std::unique_ptr<WebApp>> apps_unregistered;
+
   for (std::unique_ptr<WebApp>& web_app : update_data->apps_to_create) {
     AppId app_id = web_app->app_id();
     DCHECK(!registrar_->GetAppById(app_id));
     registrar_->registry().emplace(std::move(app_id), std::move(web_app));
   }
 
+  // update_data->apps_to_update are ignored here because we do in-place
+  // updates.
+
   for (const AppId& app_id : update_data->apps_to_delete) {
     auto it = registrar_->registry().find(app_id);
     DCHECK(it != registrar_->registry().end());
+
+    apps_unregistered.push_back(std::move(it->second));
     registrar_->registry().erase(it);
   }
+
+  return apps_unregistered;
+}
+
+void WebAppSyncBridge::UpdateSync(
+    const RegistryUpdateData& update_data,
+    syncer::MetadataChangeList* metadata_change_list) {
+  // We don't block web app subsystems on WebAppSyncBridge::MergeSyncData: we
+  // call WebAppProvider::OnRegistryControllerReady() right after
+  // change_processor()->ModelReadyToSync. As a result, subsystems may produce
+  // some local changes between OnRegistryControllerReady and MergeSyncData.
+  // Return early in this case. The processor cannot do any useful metadata
+  // tracking until MergeSyncData is called:
+  if (!change_processor()->IsTrackingMetadata())
+    return;
+
+  for (const std::unique_ptr<WebApp>& app : update_data.apps_to_create) {
+    if (app->IsSynced()) {
+      change_processor()->Put(app->app_id(), CreateSyncEntityData(*app),
+                              metadata_change_list);
+    }
+  }
+
+  // An app may obtain or may loose IsSynced flag without being deleted. We
+  // should conservatively include or exclude the app from the synced apps
+  // subset.
+  //
+  // TODO(loyso): Send an update to sync server only if any sync-specific
+  // data was changed. Implement some dirty flags in WebApp setter methods.
+  for (const WebApp* app : update_data.apps_to_update) {
+    if (app->IsSynced()) {
+      change_processor()->Put(app->app_id(), CreateSyncEntityData(*app),
+                              metadata_change_list);
+    } else {
+      change_processor()->Delete(app->app_id(), metadata_change_list);
+    }
+  }
+
+  // We should unconditionally delete from sync (in case IsSynced flag was
+  // removed during the update).
+  for (const AppId& app_id : update_data.apps_to_delete) {
+    const WebApp* app = registrar_->GetAppById(app_id);
+    DCHECK(app);
+    change_processor()->Delete(app_id, metadata_change_list);
+  }
 }
 
 void WebAppSyncBridge::OnDatabaseOpened(
@@ -195,6 +301,102 @@
   change_processor()->ReportError(error);
 }
 
+void WebAppSyncBridge::MergeLocalAppsToSync(
+    const syncer::EntityChangeList& entity_data,
+    syncer::MetadataChangeList* metadata_change_list) {
+  // Build a helper set of the sync server apps to speed up lookups. The
+  // flat_set will reuse the underlying memory of this vector. app_id is storage
+  // key.
+  std::vector<AppId> storage_keys;
+  storage_keys.reserve(entity_data.size());
+  for (const auto& change : entity_data)
+    storage_keys.push_back(change->storage_key());
+  // Sort only once.
+  base::flat_set<AppId> sync_server_apps(std::move(storage_keys));
+
+  for (const WebApp& app : registrar_->AllApps()) {
+    if (!app.IsSynced())
+      continue;
+
+    bool exists_remotely = sync_server_apps.contains(app.app_id());
+    if (!exists_remotely) {
+      change_processor()->Put(app.app_id(), CreateSyncEntityData(app),
+                              metadata_change_list);
+    }
+  }
+}
+
+void WebAppSyncBridge::ApplySyncDataChange(
+    const syncer::EntityChange& change,
+    RegistryUpdateData* update_local_data) {
+  // app_id is storage key.
+  const AppId& app_id = change.storage_key();
+
+  WebApp* existing_web_app = registrar_->GetAppByIdMutable(app_id);
+
+  // Handle deletion first.
+  if (change.type() == syncer::EntityChange::ACTION_DELETE) {
+    if (!existing_web_app) {
+      DLOG(ERROR) << "ApplySyncDataChange error: no app to delete";
+      return;
+    }
+    existing_web_app->RemoveSource(Source::kSync);
+
+    if (existing_web_app->HasAnySources())
+      update_local_data->apps_to_update.insert(existing_web_app);
+    else
+      update_local_data->apps_to_delete.push_back(app_id);
+
+    return;
+  }
+
+  // Handle EntityChange::ACTION_ADD and EntityChange::ACTION_UPDATE.
+  DCHECK(change.data().specifics.has_web_app());
+  const sync_pb::WebAppSpecifics& specifics = change.data().specifics.web_app();
+
+  if (existing_web_app) {
+    // Any entities that appear in both sets must be merged.
+    ApplySyncDataToApp(specifics, existing_web_app);
+    // Preserve web_app->is_locally_installed user's choice here.
+
+    update_local_data->apps_to_update.insert(existing_web_app);
+  } else {
+    // Any remote entities that don’t exist locally must be written to local
+    // storage.
+    auto web_app = std::make_unique<WebApp>(app_id);
+
+    // Request a followup sync-initiated install for this placeholder to fetch
+    // full local data and all the icons.
+    web_app->SetIsSyncPlaceholder(true);
+
+    ApplySyncDataToApp(specifics, web_app.get());
+
+    // For a new app, automatically choose if we want to install it locally.
+    web_app->SetIsLocallyInstalled(AreAppsLocallyInstalledByDefault());
+
+    update_local_data->apps_to_create.push_back(std::move(web_app));
+  }
+}
+
+void WebAppSyncBridge::ApplySyncChangesToRegistrar(
+    std::unique_ptr<RegistryUpdateData> update_local_data) {
+  std::vector<WebApp*> apps_to_install;
+  for (const auto& web_app : update_local_data->apps_to_create)
+    apps_to_install.push_back(web_app.get());
+
+  std::vector<std::unique_ptr<WebApp>> apps_unregistered =
+      UpdateRegistrar(std::move(update_local_data));
+
+  // Do a full follow up install for all remote entities that don’t exist
+  // locally.
+  install_delegate_->InstallWebAppsAfterSync(std::move(apps_to_install));
+
+  // Do a full follow up uninstall for all deleted remote entities that exist
+  // locally and not needed by other sources. We need to clean up disk data
+  // (icons).
+  install_delegate_->UninstallWebAppsAfterSync(std::move(apps_unregistered));
+}
+
 std::unique_ptr<syncer::MetadataChangeList>
 WebAppSyncBridge::CreateMetadataChangeList() {
   return syncer::ModelTypeStore::WriteBatch::CreateMetadataChangeList();
@@ -203,14 +405,42 @@
 base::Optional<syncer::ModelError> WebAppSyncBridge::MergeSyncData(
     std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
     syncer::EntityChangeList entity_data) {
-  NOTIMPLEMENTED();
+  DCHECK(change_processor()->IsTrackingMetadata());
+
+  auto update_local_data = std::make_unique<RegistryUpdateData>();
+
+  database_->BeginTransaction();
+
+  for (const auto& change : entity_data) {
+    DCHECK_NE(change->type(), syncer::EntityChange::ACTION_DELETE);
+    ApplySyncDataChange(*change, update_local_data.get());
+  }
+
+  MergeLocalAppsToSync(entity_data, metadata_change_list.get());
+
+  database_->CommitTransaction(
+      *update_local_data, std::move(metadata_change_list), base::DoNothing());
+
+  ApplySyncChangesToRegistrar(std::move(update_local_data));
   return base::nullopt;
 }
 
 base::Optional<syncer::ModelError> WebAppSyncBridge::ApplySyncChanges(
     std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
     syncer::EntityChangeList entity_changes) {
-  NOTIMPLEMENTED();
+  DCHECK(change_processor()->IsTrackingMetadata());
+
+  auto update_local_data = std::make_unique<RegistryUpdateData>();
+
+  database_->BeginTransaction();
+
+  for (const auto& change : entity_changes)
+    ApplySyncDataChange(*change, update_local_data.get());
+
+  database_->CommitTransaction(
+      *update_local_data, std::move(metadata_change_list), base::DoNothing());
+
+  ApplySyncChangesToRegistrar(std::move(update_local_data));
   return base::nullopt;
 }
 
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.h b/chrome/browser/web_applications/web_app_sync_bridge.h
index d150e1b..9c549b4 100644
--- a/chrome/browser/web_applications/web_app_sync_bridge.h
+++ b/chrome/browser/web_applications/web_app_sync_bridge.h
@@ -14,12 +14,14 @@
 #include "chrome/browser/web_applications/components/app_registry_controller.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
+#include "components/sync/model/entity_change.h"
 #include "components/sync/model/model_type_sync_bridge.h"
 
 class Profile;
 
 namespace syncer {
 class MetadataBatch;
+class MetadataChangeList;
 class ModelError;
 class ModelTypeChangeProcessor;
 }  // namespace syncer
@@ -27,6 +29,7 @@
 namespace web_app {
 
 class AbstractWebAppDatabaseFactory;
+class SyncInstallDelegate;
 class WebAppDatabase;
 class WebAppRegistryUpdate;
 struct RegistryUpdateData;
@@ -38,12 +41,14 @@
  public:
   WebAppSyncBridge(Profile* profile,
                    AbstractWebAppDatabaseFactory* database_factory,
-                   WebAppRegistrarMutable* registrar);
+                   WebAppRegistrarMutable* registrar,
+                   SyncInstallDelegate* install_delegate);
   // Tests may inject mocks using this ctor.
   WebAppSyncBridge(
       Profile* profile,
       AbstractWebAppDatabaseFactory* database_factory,
       WebAppRegistrarMutable* registrar,
+      SyncInstallDelegate* install_delegate,
       std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor);
   ~WebAppSyncBridge() override;
 
@@ -64,8 +69,15 @@
 
  private:
   void CheckRegistryUpdateData(const RegistryUpdateData& update_data) const;
-  // Update the in-memory model.
-  void UpdateRegistrar(std::unique_ptr<RegistryUpdateData> update_data);
+
+  // Update the in-memory model. Returns unregistered apps which may be
+  // disposed.
+  std::vector<std::unique_ptr<WebApp>> UpdateRegistrar(
+      std::unique_ptr<RegistryUpdateData> update_data);
+
+  // Update the remote sync server.
+  void UpdateSync(const RegistryUpdateData& update_data,
+                  syncer::MetadataChangeList* metadata_change_list);
 
   void OnDatabaseOpened(base::OnceClosure callback,
                         Registry registry,
@@ -74,6 +86,17 @@
 
   void ReportErrorToChangeProcessor(const syncer::ModelError& error);
 
+  // Any local entities that don’t exist remotely must be provided to sync.
+  void MergeLocalAppsToSync(const syncer::EntityChangeList& entity_data,
+                            syncer::MetadataChangeList* metadata_change_list);
+
+  void ApplySyncDataChange(const syncer::EntityChange& change,
+                           RegistryUpdateData* update_local_data);
+
+  // Update registrar and Install/Uninstall missing/excessive local apps.
+  void ApplySyncChangesToRegistrar(
+      std::unique_ptr<RegistryUpdateData> update_local_data);
+
   // syncer::ModelTypeSyncBridge:
   std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList()
       override;
@@ -90,6 +113,7 @@
 
   std::unique_ptr<WebAppDatabase> database_;
   WebAppRegistrarMutable* const registrar_;
+  SyncInstallDelegate* const install_delegate_;
 
   bool is_in_update_ = false;
 
diff --git a/chrome/browser/web_applications/web_app_sync_install_delegate.h b/chrome/browser/web_applications/web_app_sync_install_delegate.h
new file mode 100644
index 0000000..1dbfd38
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_sync_install_delegate.h
@@ -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.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_INSTALL_DELEGATE_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_INSTALL_DELEGATE_H_
+
+#include <memory>
+#include <vector>
+
+namespace web_app {
+
+class WebApp;
+
+// WebAppSyncBridge delegates sync-initiated installs and uninstalls using
+// this interface.
+class SyncInstallDelegate {
+ public:
+  virtual ~SyncInstallDelegate() = default;
+
+  // |web_apps| are already registered and owned by the registrar.
+  virtual void InstallWebAppsAfterSync(std::vector<WebApp*> web_apps) = 0;
+  // |web_apps| are already unregistered and not owned by the registrar.
+  virtual void UninstallWebAppsAfterSync(
+      std::vector<std::unique_ptr<WebApp>> web_apps) = 0;
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_INSTALL_DELEGATE_H_
diff --git a/chrome/common/channel_info.h b/chrome/common/channel_info.h
index 881a255..c2c6c3c 100644
--- a/chrome/common/channel_info.h
+++ b/chrome/common/channel_info.h
@@ -9,6 +9,10 @@
 
 #include "build/build_config.h"
 
+namespace base {
+class Environment;
+}
+
 namespace version_info {
 enum class Channel;
 }
@@ -51,6 +55,12 @@
 std::string GetChannelSuffixForDataDir();
 #endif
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// Returns the channel-specific filename of the desktop shortcut used to launch
+// the browser.
+std::string GetDesktopName(base::Environment* env);
+#endif
+
 }  // namespace chrome
 
 #endif  // CHROME_COMMON_CHANNEL_INFO_H_
diff --git a/chrome/common/channel_info_posix.cc b/chrome/common/channel_info_posix.cc
index 47a9e301..d5dfbe13 100644
--- a/chrome/common/channel_info_posix.cc
+++ b/chrome/common/channel_info_posix.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/common/channel_info.h"
 
+#include "base/environment.h"
 #include "base/strings/string_util.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
@@ -68,6 +69,30 @@
 }
 #endif  // defined(GOOGLE_CHROME_BUILD)
 
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+std::string GetDesktopName(base::Environment* env) {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  version_info::Channel product_channel(GetChannel());
+  switch (product_channel) {
+    case version_info::Channel::DEV:
+      return "google-chrome-unstable.desktop";
+    case version_info::Channel::BETA:
+      return "google-chrome-beta.desktop";
+    default:
+      return "google-chrome.desktop";
+  }
+#else  // BUILDFLAG(CHROMIUM_BRANDING)
+  // Allow $CHROME_DESKTOP to override the built-in value, so that development
+  // versions can set themselves as the default without interfering with
+  // non-official, packaged versions using the built-in value.
+  std::string name;
+  if (env->GetVar("CHROME_DESKTOP", &name) && !name.empty())
+    return name;
+  return "chromium-browser.desktop";
+#endif
+}
+#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
+
 version_info::Channel GetChannel() {
   return GetChannelImpl(nullptr, nullptr);
 }
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 31eca9aa2..d9a59c46 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -142,6 +142,16 @@
     "ThirdPartyModulesBlocking", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
+// Enables the additional TLS 1.3 server-random-based downgrade protection
+// described in https://tools.ietf.org/html/rfc8446#section-4.1.3 for
+// connections which chain to a local trust anchor. The protection is
+// unconditionally enabled for known trust anchors.
+//
+// This is a MUST-level requirement of TLS 1.3, but may have compatibility
+// issues with some outdated buggy TLS-terminating proxies.
+const base::Feature kTLS13HardeningForLocalAnchors{
+    "TLS13HardeningForLocalAnchors", base::FEATURE_DISABLED_BY_DEFAULT};
+
 #if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX)
 // Enables the dual certificate verification trial feature.
 // https://crbug.com/649026
@@ -773,10 +783,6 @@
                                               base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
-// Enables using the main HTTP cache for media files as well.
-const base::Feature kUseSameCacheForMedia{"UseSameCacheForMedia",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
-
 #if defined(OS_CHROMEOS)
 // Enables support of libcups APIs from ARC
 const base::Feature kArcCupsApi{"ArcCupsApi",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 5d891cc..e1c88f1 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -450,6 +450,9 @@
 #endif
 
 COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kTLS13HardeningForLocalAnchors;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kTreatUnsafeDownloadsAsActive;
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const char kTreatUnsafeDownloadsAsActiveParamName[];
@@ -487,9 +490,6 @@
 
 #endif
 
-COMPONENT_EXPORT(CHROME_FEATURES)
-extern const base::Feature kUseSameCacheForMedia;
-
 #if defined(OS_CHROMEOS)
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kArcCupsApi;
 
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index fb72bb9..5ff3de2 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1881,6 +1881,11 @@
 // from http to https.
 const char kHSTSPolicyBypassList[] = "hsts.policy.upgrade_bypass_list";
 
+// If true, enables stronger TLS 1.3 downgrade protection for connections using
+// local trust anchors.
+const char kTLS13HardeningForLocalAnchorsEnabled[] =
+    "ssl.tls13_hardening_for_local_anchors";
+
 // Boolean that specifies whether the built-in asynchronous DNS client is used.
 const char kBuiltInDnsClientEnabled[] = "async_dns.enabled";
 
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index c9990d3..0e527a8 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -739,6 +739,7 @@
 extern const char kCipherSuiteBlacklist[];
 extern const char kH2ClientCertCoalescingHosts[];
 extern const char kHSTSPolicyBypassList[];
+extern const char kTLS13HardeningForLocalAnchorsEnabled[];
 
 extern const char kBuiltInDnsClientEnabled[];
 extern const char kDnsOverHttpsMode[];
diff --git a/chrome/common/stack_sampling_configuration.cc b/chrome/common/stack_sampling_configuration.cc
index 35c0768e..2d8c22e 100644
--- a/chrome/common/stack_sampling_configuration.cc
+++ b/chrome/common/stack_sampling_configuration.cc
@@ -15,6 +15,10 @@
 #include "content/public/common/content_switches.h"
 #include "extensions/buildflags/buildflags.h"
 
+#if defined(OS_WIN)
+#include "base/win/static_constants.h"
+#endif
+
 #if defined(OS_MACOSX)
 #include "base/mac/mac_util.h"
 #endif
@@ -189,6 +193,13 @@
   if (!IsProfilerSupported())
     return PROFILE_DISABLED;
 
+#if defined(OS_WIN)
+  // Do not start the profiler when Application Verifier is in use; running them
+  // simultaneously can cause crashes and has no known use case.
+  if (GetModuleHandleA(base::win::kApplicationVerifierDllName))
+    return PROFILE_DISABLED;
+#endif
+
   switch (chrome::GetChannel()) {
     // Enable the profiler unconditionally for development/waterfall builds.
     case version_info::Channel::UNKNOWN:
diff --git a/chrome/renderer/translate/translate_helper_browsertest.cc b/chrome/renderer/translate/translate_helper_browsertest.cc
index 036ce2b1d..09ac5dc 100644
--- a/chrome/renderer/translate/translate_helper_browsertest.cc
+++ b/chrome/renderer/translate/translate_helper_browsertest.cc
@@ -92,8 +92,7 @@
     trans_result_error_type_ = translate::TranslateErrors::NONE;
 
     // Will get new result values via OnPageTranslated.
-    Translate(translate_script, network::mojom::URLLoaderFactoryPtr(),
-              source_lang, target_lang,
+    Translate(translate_script, source_lang, target_lang,
               base::Bind(&TestTranslateHelper::OnPageTranslated,
                          base::Unretained(this)));
   }
diff --git a/chrome/renderer/url_loader_throttle_provider_impl.cc b/chrome/renderer/url_loader_throttle_provider_impl.cc
index 073f441..1642d5d 100644
--- a/chrome/renderer/url_loader_throttle_provider_impl.cc
+++ b/chrome/renderer/url_loader_throttle_provider_impl.cc
@@ -73,12 +73,6 @@
 
 void SetExtensionThrottleManagerTestPolicy(
     extensions::ExtensionThrottleManager* extension_throttle_manager) {
-  // Requests issued within within |kUserGestureWindowMs| of a user gesture
-  // are also considered as user gestures (see
-  // resource_dispatcher_host_impl.cc), so these tests need to bypass the
-  // checking of the net::LOAD_MAYBE_USER_GESTURE load flag in the manager
-  // in order to test the throttling logic.
-  extension_throttle_manager->SetIgnoreUserGestureLoadFlagForTests(true);
   std::unique_ptr<net::BackoffEntry::Policy> policy(
       new net::BackoffEntry::Policy{
           // Number of initial errors (in sequence) to ignore before
diff --git a/chrome/services/isolated_xr_device/xr_runtime_provider.cc b/chrome/services/isolated_xr_device/xr_runtime_provider.cc
index aa6ea55..e54480a 100644
--- a/chrome/services/isolated_xr_device/xr_runtime_provider.cc
+++ b/chrome/services/isolated_xr_device/xr_runtime_provider.cc
@@ -39,7 +39,7 @@
 
 template <typename VrDeviceT>
 std::unique_ptr<VrDeviceT> EnableRuntime(
-    device::mojom::IsolatedXRRuntimeProviderClientPtr& client) {
+    device::mojom::IsolatedXRRuntimeProviderClient* client) {
   auto device = std::make_unique<VrDeviceT>();
   TRACE_EVENT_INSTANT1("xr", "HardwareAdded", TRACE_EVENT_SCOPE_THREAD, "id",
                        static_cast<int>(device->GetId()));
@@ -52,7 +52,7 @@
 }
 
 template <typename VrDeviceT>
-void DisableRuntime(device::mojom::IsolatedXRRuntimeProviderClientPtr& client,
+void DisableRuntime(device::mojom::IsolatedXRRuntimeProviderClient* client,
                     std::unique_ptr<VrDeviceT> device) {
   TRACE_EVENT_INSTANT1("xr", "HardwareRemoved", TRACE_EVENT_SCOPE_THREAD, "id",
                        static_cast<int>(device->GetId()));
@@ -62,7 +62,7 @@
 }
 
 template <typename VrHardwareT>
-void SetRuntimeStatus(device::mojom::IsolatedXRRuntimeProviderClientPtr& client,
+void SetRuntimeStatus(device::mojom::IsolatedXRRuntimeProviderClient* client,
                       IsolatedXRRuntimeProvider::RuntimeStatus status,
                       std::unique_ptr<VrHardwareT>* out_device) {
   if (status == IsolatedXRRuntimeProvider::RuntimeStatus::kEnable &&
@@ -171,9 +171,10 @@
 }
 
 void IsolatedXRRuntimeProvider::RequestDevices(
-    device::mojom::IsolatedXRRuntimeProviderClientPtr client) {
+    mojo::PendingRemote<device::mojom::IsolatedXRRuntimeProviderClient>
+        client) {
   // Start polling to detect devices being added/removed.
-  client_ = std::move(client);
+  client_.Bind(std::move(client));
   SetupPollingForDeviceChanges();
   client_->OnDevicesEnumerated();
 }
@@ -186,7 +187,7 @@
 }
 
 void IsolatedXRRuntimeProvider::SetOculusVrRuntimeStatus(RuntimeStatus status) {
-  SetRuntimeStatus(client_, status, &oculus_device_);
+  SetRuntimeStatus(client_.get(), status, &oculus_device_);
 }
 #endif  // BUILDFLAG(ENABLE_OCULUS_VR)
 
@@ -198,7 +199,7 @@
 }
 
 void IsolatedXRRuntimeProvider::SetOpenVrRuntimeStatus(RuntimeStatus status) {
-  SetRuntimeStatus(client_, status, &openvr_device_);
+  SetRuntimeStatus(client_.get(), status, &openvr_device_);
 }
 #endif  // BUILDFLAG(ENABLE_OPENVR)
 
@@ -208,7 +209,7 @@
 }
 
 void IsolatedXRRuntimeProvider::SetWMRRuntimeStatus(RuntimeStatus status) {
-  SetRuntimeStatus(client_, status, &wmr_device_);
+  SetRuntimeStatus(client_.get(), status, &wmr_device_);
 }
 #endif  // BUILDFLAG(ENABLE_WINDOWS_MR)
 
@@ -218,7 +219,7 @@
 }
 
 void IsolatedXRRuntimeProvider::SetOpenXrRuntimeStatus(RuntimeStatus status) {
-  SetRuntimeStatus(client_, status, &openxr_device_);
+  SetRuntimeStatus(client_.get(), status, &openxr_device_);
 }
 #endif  // BUILDFLAG(ENABLE_OPENXR)
 
diff --git a/chrome/services/isolated_xr_device/xr_runtime_provider.h b/chrome/services/isolated_xr_device/xr_runtime_provider.h
index 1d8b8784..4cdf647e 100644
--- a/chrome/services/isolated_xr_device/xr_runtime_provider.h
+++ b/chrome/services/isolated_xr_device/xr_runtime_provider.h
@@ -9,6 +9,8 @@
 
 #include "device/vr/buildflags/buildflags.h"
 #include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace device {
 class OculusDevice;
@@ -25,7 +27,8 @@
   ~IsolatedXRRuntimeProvider() final;
 
   void RequestDevices(
-      device::mojom::IsolatedXRRuntimeProviderClientPtr client) override;
+      mojo::PendingRemote<device::mojom::IsolatedXRRuntimeProviderClient>
+          client) override;
 
   enum class RuntimeStatus;
 
@@ -62,7 +65,7 @@
   std::unique_ptr<device::OpenXrDevice> openxr_device_;
 #endif
 
-  device::mojom::IsolatedXRRuntimeProviderClientPtr client_;
+  mojo::Remote<device::mojom::IsolatedXRRuntimeProviderClient> client_;
   base::WeakPtrFactory<IsolatedXRRuntimeProvider> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 2fe8390..3b0f5ae 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2547,6 +2547,8 @@
       sources += [
         "../browser/supervised_user/logged_in_user_mixin.cc",
         "../browser/supervised_user/logged_in_user_mixin.h",
+        "../browser/supervised_user/permission_request_creator_mock.cc",
+        "../browser/supervised_user/permission_request_creator_mock.h",
         "../browser/supervised_user/supervised_user_navigation_throttle_browsertest.cc",
         "../browser/supervised_user/supervised_user_service_browsertest.cc",
         "../browser/supervised_user/supervised_user_url_filter_browsertest.cc",
diff --git a/chrome/test/base/js2gtest.gni b/chrome/test/base/js2gtest.gni
index 4188269a..fcd5c7d 100644
--- a/chrome/test/base/js2gtest.gni
+++ b/chrome/test/base/js2gtest.gni
@@ -19,144 +19,134 @@
 #   defines
 #   deps
 #   visibility
-if (is_win && host_os != "win") {
-  # Running v8_shell for the host doesn't work in cross builds,
-  # https://crbug.com/1010561
-  template("js2gtest") {
-    not_needed(invoker, "*")
-    group(target_name) {
+template("js2gtest") {
+  assert(defined(invoker.test_type) &&
+         (invoker.test_type == "webui" || invoker.test_type == "unit" ||
+          invoker.test_type == "extension" ||
+          invoker.test_type == "mojo_lite_webui"))
+  action_name = target_name + "_action"
+  source_set_name = target_name
+
+  # The mapping from sources to the copied version.
+  copied_source_pattern = "$root_out_dir/test_data/{{source_root_relative_dir}}/{{source_file_part}}"
+
+  gen_source_pattern = "{{source_gen_dir}}/{{source_name_part}}-gen.cc"
+
+  data = []
+  if (defined(invoker.data)) {
+    data += invoker.data
+  }
+
+  action_foreach(action_name) {
+    testonly = true
+    visibility = [ ":$source_set_name" ]
+    script = "//tools/gypv8sh.py"
+
+    sources = invoker.sources
+
+    v8_shell_path = get_label_info("//v8:v8_shell($v8_snapshot_toolchain)",
+                                   "root_out_dir") + "/v8_shell"
+    if (host_os == "win") {
+      v8_shell_path += ".exe"
+    }
+
+    input_js = [
+      "//chrome/third_party/mock4js/mock4js.js",
+      "//chrome/test/data/webui/test_api.js",
+      "//chrome/test/base/js2gtest.js",
+    ]
+    inputs = [ v8_shell_path ] + input_js
+    if (defined(invoker.deps_js)) {
+      inputs += [ invoker.deps_js ]
+    }
+    if (defined(invoker.gen_include_files)) {
+      inputs += invoker.gen_include_files
+    }
+
+    # Outputs. The script will copy the source files to the output directory,
+    # which then must be treated as runtime data. The generated .cc file isn't
+    # data, it will be compiled in a step below.
+    outputs = [
+      copied_source_pattern,
+      gen_source_pattern,
+    ]
+    data += process_file_template(sources, [ copied_source_pattern ])
+
+    args = []
+    if (defined(invoker.deps_js)) {
+      args += [
+        "--deps_js",
+        rebase_path(invoker.deps_js, root_build_dir),
+      ]
+    }
+    args += [
+      # Need "./" for script to find binary (cur dir is not on path).
+      "./" + rebase_path(v8_shell_path, root_build_dir),
+    ]
+    args += rebase_path(input_js, root_build_dir) + [ invoker.test_type ]
+    if (v8_use_external_startup_data) {
+      args += [ "--external=y" ]
+    } else {
+      args += [ "--external=n" ]
+    }
+    args += [
+      "{{source}}",
+      rebase_path("//", root_build_dir),  # Path to source root.
+      gen_source_pattern,
+      rebase_path(copied_source_pattern, root_build_dir),
+    ]
+
+    deps = [
+      "//v8:v8_shell($v8_snapshot_toolchain)",
+    ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
     }
   }
-} else {
-  template("js2gtest") {
-    assert(defined(invoker.test_type) &&
-           (invoker.test_type == "webui" || invoker.test_type == "unit" ||
-            invoker.test_type == "extension" ||
-            invoker.test_type == "mojo_lite_webui"))
-    action_name = target_name + "_action"
-    source_set_name = target_name
 
-    # The mapping from sources to the copied version.
-    copied_source_pattern = "$root_out_dir/test_data/{{source_root_relative_dir}}/{{source_file_part}}"
-
-    gen_source_pattern = "{{source_gen_dir}}/{{source_name_part}}-gen.cc"
-
-    data = []
-    if (defined(invoker.data)) {
-      data += invoker.data
-    }
-
-    action_foreach(action_name) {
-      testonly = true
+  if (defined(invoker.extra_js_files)) {
+    copy_target_name = target_name + "_copy"
+    copy(copy_target_name) {
       visibility = [ ":$source_set_name" ]
-      script = "//tools/gypv8sh.py"
-
-      sources = invoker.sources
-
-      v8_shell_path = get_label_info("//v8:v8_shell($v8_snapshot_toolchain)",
-                                     "root_out_dir") + "/v8_shell"
-      if (host_os == "win") {
-        v8_shell_path += ".exe"
-      }
-
-      input_js = [
-        "//chrome/third_party/mock4js/mock4js.js",
-        "//chrome/test/data/webui/test_api.js",
-        "//chrome/test/base/js2gtest.js",
-      ]
-      inputs = [ v8_shell_path ] + input_js
-      if (defined(invoker.deps_js)) {
-        inputs += [ invoker.deps_js ]
-      }
-      if (defined(invoker.gen_include_files)) {
-        inputs += invoker.gen_include_files
-      }
-
-      # Outputs. The script will copy the source files to the output directory,
-      # which then must be treated as runtime data. The generated .cc file isn't
-      # data, it will be compiled in a step below.
+      sources = invoker.extra_js_files
       outputs = [
         copied_source_pattern,
-        gen_source_pattern,
       ]
-      data += process_file_template(sources, [ copied_source_pattern ])
-
-      args = []
-      if (defined(invoker.deps_js)) {
-        args += [
-          "--deps_js",
-          rebase_path(invoker.deps_js, root_build_dir),
-        ]
-      }
-      args += [
-        # Need "./" for script to find binary (cur dir is not on path).
-        "./" + rebase_path(v8_shell_path, root_build_dir),
-      ]
-      args += rebase_path(input_js, root_build_dir) + [ invoker.test_type ]
-      if (v8_use_external_startup_data) {
-        args += [ "--external=y" ]
-      } else {
-        args += [ "--external=n" ]
-      }
-      args += [
-        "{{source}}",
-        rebase_path("//", root_build_dir),  # Path to source root.
-        gen_source_pattern,
-        rebase_path(copied_source_pattern, root_build_dir),
-      ]
-
-      deps = [
-        "//v8:v8_shell($v8_snapshot_toolchain)",
-      ]
-      if (defined(invoker.deps)) {
-        deps += invoker.deps
-      }
     }
+  }
 
+  source_set(source_set_name) {
+    testonly = true
+    forward_variables_from(invoker,
+                           [
+                             "defines",
+                             "visibility",
+                           ])
+    sources = process_file_template(invoker.sources, [ gen_source_pattern ])
+
+    # This empty public header is intentional to remove unnecessary build
+    # dependency.
+    public = []
+
+    deps = [
+      ":$action_name",
+
+      # The generator implicitly makes includes from these targets.
+      "//chrome/test:test_support",
+      "//testing/gmock",
+      "//testing/gtest",
+      "//url",
+    ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+    if (defined(invoker.gen_include_files)) {
+      data += invoker.gen_include_files
+    }
     if (defined(invoker.extra_js_files)) {
-      copy_target_name = target_name + "_copy"
-      copy(copy_target_name) {
-        visibility = [ ":$source_set_name" ]
-        sources = invoker.extra_js_files
-        outputs = [
-          copied_source_pattern,
-        ]
-      }
-    }
-
-    source_set(source_set_name) {
-      testonly = true
-      forward_variables_from(invoker,
-                             [
-                               "defines",
-                               "visibility",
-                             ])
-      sources = process_file_template(invoker.sources, [ gen_source_pattern ])
-
-      # This empty public header is intentional to remove unnecessary build
-      # dependency.
-      public = []
-
-      deps = [
-        ":$action_name",
-
-        # The generator implicitly makes includes from these targets.
-        "//chrome/test:test_support",
-        "//testing/gmock",
-        "//testing/gtest",
-        "//url",
+      data_deps = [
+        ":$copy_target_name",
       ]
-      if (defined(invoker.deps)) {
-        deps += invoker.deps
-      }
-      if (defined(invoker.gen_include_files)) {
-        data += invoker.gen_include_files
-      }
-      if (defined(invoker.extra_js_files)) {
-        data_deps = [
-          ":$copy_target_name",
-        ]
-      }
     }
   }
 }
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc
index 4141501..4b89caa9 100644
--- a/chrome/test/base/test_browser_window.cc
+++ b/chrome/test/base/test_browser_window.cc
@@ -143,7 +143,9 @@
   return false;
 }
 
-void TestBrowserWindow::ShowAvatarHighlightAnimation() {}
+autofill::AutofillBubbleHandler* TestBrowserWindow::GetAutofillBubbleHandler() {
+  return &autofill_bubble_handler_;
+}
 
 ToolbarActionsBar* TestBrowserWindow::GetToolbarActionsBar() {
   return nullptr;
@@ -202,27 +204,12 @@
   return nullptr;
 }
 
-autofill::SaveCardBubbleView* TestBrowserWindow::ShowSaveCreditCardBubble(
-    content::WebContents* contents,
-    autofill::SaveCardBubbleController* controller,
-    bool user_gesture) {
-  return nullptr;
-}
-
 SharingDialog* TestBrowserWindow::ShowSharingDialog(
     content::WebContents* web_contents,
     SharingUiController* controller) {
   return nullptr;
 }
 
-autofill::LocalCardMigrationBubble*
-TestBrowserWindow::ShowLocalCardMigrationBubble(
-    content::WebContents* contents,
-    autofill::LocalCardMigrationBubbleController* controller,
-    bool user_gesture) {
-  return nullptr;
-}
-
 send_tab_to_self::SendTabToSelfBubbleView*
 TestBrowserWindow::ShowSendTabToSelfBubble(
     content::WebContents* contents,
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index 47031d9..6ea5d92 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "chrome/browser/download/test_download_shelf.h"
+#include "chrome/browser/ui/autofill/test/test_autofill_bubble_handler.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -99,7 +100,7 @@
   bool IsFullscreenBubbleVisible() const override;
   LocationBar* GetLocationBar() const override;
   bool UpdatePageActionIcon(PageActionIconType type) override;
-  void ShowAvatarHighlightAnimation() override;
+  autofill::AutofillBubbleHandler* GetAutofillBubbleHandler() override;
   void ExecutePageActionIconForTesting(PageActionIconType type) override {}
   void SetFocusToLocationBar(bool select_all) override {}
   void UpdateReloadStopState(bool is_loading, bool force) override {}
@@ -140,14 +141,6 @@
                               PageActionIconType icon_type,
                               IntentPickerResponse callback) override {}
 #endif  //  !define(OS_ANDROID)
-  autofill::SaveCardBubbleView* ShowSaveCreditCardBubble(
-      content::WebContents* contents,
-      autofill::SaveCardBubbleController* controller,
-      bool user_gesture) override;
-  autofill::LocalCardMigrationBubble* ShowLocalCardMigrationBubble(
-      content::WebContents* contents,
-      autofill::LocalCardMigrationBubbleController* controller,
-      bool user_gesture) override;
   send_tab_to_self::SendTabToSelfBubbleView* ShowSendTabToSelfBubble(
       content::WebContents* contents,
       send_tab_to_self::SendTabToSelfBubbleController* controller,
@@ -228,6 +221,7 @@
     DISALLOW_COPY_AND_ASSIGN(TestLocationBar);
   };
 
+  autofill::TestAutofillBubbleHandler autofill_bubble_handler_;
   TestDownloadShelf download_shelf_;
   TestLocationBar location_bar_;
 
diff --git a/chrome/test/base/ui_test_utils.cc b/chrome/test/base/ui_test_utils.cc
index 1b974c3..cc78d77 100644
--- a/chrome/test/base/ui_test_utils.cc
+++ b/chrome/test/base/ui_test_utils.cc
@@ -219,7 +219,7 @@
 
   // OmniboxControllerEmitter::Observer:
   void OnOmniboxQuery(AutocompleteController* controller,
-                      const base::string16& input_text) override {}
+                      const AutocompleteInput& input) override {}
   void OnOmniboxResultChanged(bool default_match_changed,
                               AutocompleteController* controller) override {
     if (run_loop_.running())
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
index 092c250..4285fc9 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
@@ -79,8 +79,8 @@
                                        const std::string& id)
     : socket_(factory.Run()),
       url_(url),
-      parent_(nullptr),
       owner_(nullptr),
+      parent_(nullptr),
       crashed_(false),
       detached_(false),
       id_(id),
@@ -99,8 +99,8 @@
     const FrontendCloserFunc& frontend_closer_func)
     : socket_(factory.Run()),
       url_(url),
-      parent_(nullptr),
       owner_(nullptr),
+      parent_(nullptr),
       crashed_(false),
       detached_(false),
       id_(id),
@@ -114,9 +114,9 @@
 
 DevToolsClientImpl::DevToolsClientImpl(DevToolsClientImpl* parent,
                                        const std::string& session_id)
-    : parent_(parent),
-      owner_(nullptr),
+    : owner_(nullptr),
       session_id_(session_id),
+      parent_(parent),
       crashed_(false),
       detached_(false),
       id_(session_id),
@@ -136,8 +136,8 @@
     const ParserFunc& parser_func)
     : socket_(factory.Run()),
       url_(url),
-      parent_(nullptr),
       owner_(nullptr),
+      parent_(nullptr),
       crashed_(false),
       detached_(false),
       id_(id),
@@ -297,6 +297,10 @@
 
 DevToolsClientImpl::ResponseInfo::~ResponseInfo() {}
 
+DevToolsClientImpl* DevToolsClientImpl::GetRootClient() {
+  return parent_ ? parent_ : this;
+}
+
 Status DevToolsClientImpl::SendCommandInternal(
     const std::string& method,
     const base::DictionaryValue& params,
@@ -324,8 +328,7 @@
     VLOG(1) << "DevTools WebSocket Command: " << method << " (id=" << command_id
             << ") " << id_ << " " << FormatValueForDisplay(params);
   }
-  SyncWebSocket* socket =
-      (parent_ != nullptr) ? parent_->socket_.get() : socket_.get();
+  SyncWebSocket* socket = GetRootClient()->socket_.get();
   if (!socket->Send(message)) {
     return Status(kDisconnected, "unable to send message to renderer");
   }
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.h b/chrome/test/chromedriver/chrome/devtools_client_impl.h
index 4234e3a..8e12cb5 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.h
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.h
@@ -120,6 +120,7 @@
   Status HandleReceivedEvents() override;
   void SetDetached() override;
   void SetOwner(WebViewImpl* owner) override;
+  DevToolsClientImpl* GetRootClient();
 
  private:
   enum ResponseState {
@@ -164,10 +165,13 @@
 
   std::unique_ptr<SyncWebSocket> socket_;
   GURL url_;
-  DevToolsClientImpl* parent_;
   // WebViewImpl that owns this instance; nullptr for browser-wide DevTools.
   WebViewImpl* owner_;
   const std::string session_id_;
+  // parent_ / children_: it's a flat hierarchy - nesting is at most one level
+  // deep. children_ holds child sessions - identified by their session id -
+  // which send/receive messages via the socket_ of their parent.
+  DevToolsClientImpl* parent_;
   std::map<std::string, DevToolsClientImpl*> children_;
   bool crashed_;
   bool detached_;
diff --git a/chrome/test/chromedriver/chrome/status.h b/chrome/test/chromedriver/chrome/status.h
index 1b745ef..098746a9 100644
--- a/chrome/test/chromedriver/chrome/status.h
+++ b/chrome/test/chromedriver/chrome/status.h
@@ -42,6 +42,7 @@
   kForbidden = 103,
   kTabCrashed,
   kTargetDetached,
+  kUnexpectedAlertOpen_Keep,
 };
 
 // Represents a WebDriver status, which may be an error or ok.
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.cc b/chrome/test/chromedriver/chrome/web_view_impl.cc
index c711b018..d4108f0 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.cc
+++ b/chrome/test/chromedriver/chrome/web_view_impl.cc
@@ -195,10 +195,14 @@
 
 WebViewImpl* WebViewImpl::CreateChild(const std::string& session_id,
                                       const std::string& target_id) const {
-  DevToolsClientImpl* parent_client =
-      static_cast<DevToolsClientImpl*>(client_.get());
+  // While there may be a deep hierarchy of WebViewImpl instances, the
+  // hierarchy for DevToolsClientImpl is flat - there's a root which
+  // sends/receives over the socket, and all child sessions are considered
+  // its children (one level deep at most).
+  DevToolsClientImpl* root_client =
+      static_cast<DevToolsClientImpl*>(client_.get())->GetRootClient();
   std::unique_ptr<DevToolsClient> child_client(
-      std::make_unique<DevToolsClientImpl>(parent_client, session_id));
+      std::make_unique<DevToolsClientImpl>(root_client, session_id));
   WebViewImpl* child = new WebViewImpl(target_id, w3c_compliant_, browser_info_,
                                        std::move(child_client), nullptr,
                                        navigation_tracker_->IsNonBlocking()
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index b3d7522..2c57cac 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -948,52 +948,55 @@
   def testActionsMultiTouchPoint(self):
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
     self._driver.ExecuteScript(
-        'document.body.innerHTML = "<div>old</div>";'
-        'var div = document.getElementsByTagName("div")[0];'
-        'window.events = [];'
-        'div.style["width"] = "100px";'
-        'div.style["height"] = "100px";'
-        'div.addEventListener("touchstart", function(e) {'
-        '  window.events.push('
-        '      {type: e.type,'
-        '       x: e.touches[e.touches.length - 1].clientX,'
-        '       y: e.touches[e.touches.length - 1].clientY});'
-        '});'
-        'div.addEventListener("touchend", function(e) {'
-        '  window.events.push('
-        '      {type: e.type});'
-        '});')
+        '''
+        document.body.innerHTML
+          = "<div id='div' autofocus style='width:200px; height:200px'>";
+        window.events = [];
+        const div = document.getElementById('div');
+        div.addEventListener('touchstart', event => {
+          window.events.push(
+              {type: event.type,
+               x: event.touches[event.touches.length - 1].clientX,
+               y: event.touches[event.touches.length - 1].clientY});
+        });
+        div.addEventListener('touchend', event => {
+          window.events.push(
+              {type: event.type});
+        });
+        ''')
+
     actions = ({"actions": [{
       "type":"pointer",
-      "actions":[{"type": "pointerMove", "x": 10, "y": 10},
+      "actions":[{"type": "pointerMove", "x": 50, "y": 50},
                  {"type": "pointerDown"},
                  {"type": "pointerUp"}],
       "parameters": {"pointerType": "touch"},
       "id": "pointer1"},
       {
       "type":"pointer",
-      "actions":[{"type": "pointerMove", "x": 15, "y": 15},
+      "actions":[{"type": "pointerMove", "x": 60, "y": 60},
                  {"type": "pointerDown"},
                  {"type": "pointerUp"}],
       "parameters": {"pointerType": "touch"},
       "id": "pointer2"}]})
     self._driver.PerformActions(actions)
+    time.sleep(1)
     for _ in range(5):
       events = self._driver.ExecuteScript('return window.events')
       if len(events) == 4:
         break
-      # Wait 10 ms for the event handler to be executed.
-      time.sleep(0.01)
+      # Wait 100 more ms for the event handler to be executed.
+      time.sleep(0.1)
 
     self.assertEquals(4, len(events))
     self.assertEquals("touchstart", events[0]['type'])
     self.assertEquals("touchstart", events[1]['type'])
     self.assertEquals("touchend", events[2]['type'])
     self.assertEquals("touchend", events[3]['type'])
-    self.assertEquals(10, events[0]['x'])
-    self.assertEquals(10, events[0]['y'])
-    self.assertEquals(15, events[1]['x'])
-    self.assertEquals(15, events[1]['y'])
+    self.assertEquals(50, events[0]['x'])
+    self.assertEquals(50, events[0]['y'])
+    self.assertEquals(60, events[1]['x'])
+    self.assertEquals(60, events[1]['y'])
 
   def testActionsMulti(self):
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index 52abaf6..c0b57a9 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -512,6 +512,8 @@
     return nav_status;
   if (status.code() == kUnexpectedAlertOpen)
     return Status(kOk);
+  if (status.code() == kUnexpectedAlertOpen_Keep)
+    return Status(kUnexpectedAlertOpen);
   return status;
 }
 
@@ -1773,7 +1775,14 @@
   std::string screenshot;
   status = web_view->CaptureScreenshot(&screenshot, base::DictionaryValue());
   if (status.IsError()) {
-    LOG(WARNING) << "screenshot failed, retrying";
+    if (status.code() == kUnexpectedAlertOpen) {
+      LOG(WARNING) << status.message() << ", cancelling screenshot";
+      // we can't take screenshot in this state
+      // but we must return kUnexpectedAlertOpen_Keep instead
+      // see https://crbug.com/chromedriver/2117
+      return Status(kUnexpectedAlertOpen_Keep);
+    }
+    LOG(WARNING) << "screenshot failed, retrying " << status.message();
     status = web_view->CaptureScreenshot(&screenshot, base::DictionaryValue());
   }
   if (status.IsError())
diff --git a/chrome/test/data/appcache/french_page_with_appcache.html b/chrome/test/data/appcache/french_page_with_appcache.html
deleted file mode 100644
index 16df202b..0000000
--- a/chrome/test/data/appcache/french_page_with_appcache.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html manifest="simple_page.manifest">
-<head>
-  <head><title>Cette page est en Français</title></head>
-  <script type="text/javascript">
-    function onCachedEvent() {
-      window.document.title = "AppCache mis à jour";
-    }
-
-    function onLoad() {
-      window.applicationCache.addEventListener('cached', onCachedEvent, false);
-    }
-  </script>
-</head>
-<body onload="onLoad()">
-Cette page a été rédigée en français. Saviez-vous que le Français est la langue officielle des jeux olympiques? Ça vous en bouche un coin, pas vrai?
-</body>
-</html>
diff --git a/chrome/test/data/appcache/simple_page.manifest b/chrome/test/data/appcache/simple_page.manifest
deleted file mode 100644
index a6f40c55..0000000
--- a/chrome/test/data/appcache/simple_page.manifest
+++ /dev/null
@@ -1,4 +0,0 @@
-CACHE MANIFEST
-
-NETWORK:
-*
diff --git a/chrome/test/data/local_ntp/realbox_browsertest.js b/chrome/test/data/local_ntp/realbox_browsertest.js
index c81b4b78..c18732e 100644
--- a/chrome/test/data/local_ntp/realbox_browsertest.js
+++ b/chrome/test/data/local_ntp/realbox_browsertest.js
@@ -19,6 +19,7 @@
  * @const
  */
 test.realbox.CLASSES = {
+  REMOVABLE: 'removable',
   REMOVE_ICON: 'remove-icon',
   SELECTED: 'selected',
   SHOW_MATCHES: 'show-matches',
@@ -513,6 +514,9 @@
   test.realbox.realboxEl.dispatchEvent(keyEvent);
   assertFalse(keyEvent.defaultPrevented);
 
+  const matchesEl = $(test.realbox.IDS.REALBOX_MATCHES);
+  assertFalse(matchesEl.classList.contains(test.realbox.CLASSES.REMOVABLE));
+
   // The below 2 statements shouldn't really happen in updated code but isn't
   // terrible idea to keep testing for now. This is because SupportsDeletion()
   // is now propagated to the client, so we shouldn't allow users (via the UI)
@@ -533,6 +537,9 @@
   chrome.embeddedSearch.searchBox.onqueryautocompletedone(
       {input: test.realbox.realboxEl.value, matches});
 
+  const matchesEl = $(test.realbox.IDS.REALBOX_MATCHES);
+  assertTrue(matchesEl.classList.contains(test.realbox.CLASSES.REMOVABLE));
+
   const downArrow = new KeyboardEvent('keydown', {
     bubbles: true,
     cancelable: true,
@@ -541,9 +548,9 @@
   test.realbox.realboxEl.dispatchEvent(downArrow);
   assertTrue(downArrow.defaultPrevented);
 
-  const matchEls = $(test.realbox.IDS.REALBOX_MATCHES).children;
-  assertEquals(2, matchEls.length);
-  assertTrue(matchEls[1].classList.contains(test.realbox.CLASSES.SELECTED));
+  assertEquals(2, matchesEl.children.length);
+  assertTrue(
+      matchesEl.children[1].classList.contains(test.realbox.CLASSES.SELECTED));
 
   const shiftDelete = new KeyboardEvent('keydown', {
     bubbles: true,
@@ -571,9 +578,24 @@
   chrome.embeddedSearch.searchBox.onqueryautocompletedone(
       {input: test.realbox.realboxEl.value, matches});
 
-  const sel = `#${test.realbox.IDS.REALBOX_MATCHES}
-               .${test.realbox.CLASSES.REMOVE_ICON}`;
-  document.querySelector(sel).click();
+  const matchesEl = $(test.realbox.IDS.REALBOX_MATCHES);
+  assertTrue(matchesEl.classList.contains(test.realbox.CLASSES.REMOVABLE));
+
+  const enter = new KeyboardEvent('keydown', {
+    bubbles: true,
+    cancelable: true,
+    key: 'Enter',
+  });
+
+  let clicked = false;
+  matchesEl.children[0].onclick = () => clicked = true;
+
+  const icon = matchesEl.querySelector(`.${test.realbox.CLASSES.REMOVE_ICON}`);
+  icon.dispatchEvent(enter);
+
+  assertFalse(clicked);
+
+  icon.click();
 
   assertEquals(1, test.realbox.deletedLines.length);
   assertEquals(0, test.realbox.deletedLines[0]);
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index cd8f936..69e49a5 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -5274,5 +5274,13 @@
         "local_state":  true
       }
     ]
+  },
+
+  "TLS13HardeningForLocalAnchorsEnabled": {
+    "os": ["win", "linux", "mac", "chromeos", "android"],
+    "test_policy": { "TLS13HardeningForLocalAnchorsEnabled": true },
+    "pref_mappings": [
+      { "pref": "ssl.tls13_hardening_for_local_anchors", "local_state": true }
+    ]
   }
 }
diff --git a/chrome/test/data/previews/search_results_page.html b/chrome/test/data/previews/search_results_page.html
index d001c49..0bff136b 100644
--- a/chrome/test/data/previews/search_results_page.html
+++ b/chrome/test/data/previews/search_results_page.html
@@ -11,5 +11,6 @@
     <a id="diffHref" href="https://example.com/bar.html">diff</a>
     <a id="diffHref" href="https://example.com/baz.html">diff</a>
     <a id="diffHref" href="https://example2.com/foo.html">diff</a>
+    <a id="diffHref" href="https://example3.com/foo.html">diff</a>
   </body>
 </html>
\ No newline at end of file
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_inline_viewer_available.html b/chrome/test/data/xr/e2e_test_files/html/test_inline_viewer_available.html
index d5d86ee..56bd3f3 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_inline_viewer_available.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_inline_viewer_available.html
@@ -30,8 +30,9 @@
       // TODO (crbug.com/934912): Consider improving flow once methods are
       // updated.
       let step = "supportsInline";
-      navigator.xr.supportsSession('inline')
-      .then(()=> {
+      navigator.xr.isSessionSupported('inline')
+      .then((supported)=> {
+        assert_true(supported);
         step = "requestSession";
         return navigator.xr.requestSession('inline');
       })
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_webxr_capabilities.html b/chrome/test/data/xr/e2e_test_files/html/test_webxr_capabilities.html
index be573db..cfca458 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_webxr_capabilities.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_webxr_capabilities.html
@@ -29,16 +29,12 @@
         let expected = expectations[device];
         var supportsNonImmersive;
         var supportsImmersive;
-        navigator.xr.supportsSession('inline').then( () => {
-          supportsNonImmersive = true;
-        }, () => {
-          supportsNonImmersive = false;
+        navigator.xr.isSessionSupported('inline').then((supported) => {
+          supportsNonImmersive = supported;
         }).then( () => {
-          navigator.xr.supportsSession('immersive-vr').then( () => {
-            supportsImmersive = true;
-          }, () => {
-            supportsImmersive = false;
-          }).then( () => {
+          navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
+            supportsImmersive = supported;
+          }).then(() => {
             assert_equals(supportsNonImmersive, expected["non-immersive"],
                 'Device supports non-immersive sessions');
             assert_equals(supportsImmersive, expected["immersive"],
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_webxr_does_not_return_device.html b/chrome/test/data/xr/e2e_test_files/html/test_webxr_does_not_return_device.html
index bc5483b..9e1ede2f 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_webxr_does_not_return_device.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_webxr_does_not_return_device.html
@@ -11,9 +11,8 @@
     <script src="../../../../../../third_party/blink/web_tests/resources/testharness.js"></script>
     <script src="../resources/webxr_e2e.js"></script>
     <script>
-      navigator.xr.supportsSession('immersive-vr').then( () => {
-        assert_unreached("WebXR indicated support for 'immersive-vr'");
-      }, () => {
+      navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
+        assert_false(supported, "WebXR indicated support for 'immersive-vr'");
         done();
       });
     </script>
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index bd678b0..b36acd6 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -59,6 +59,7 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_switches.h"
@@ -501,12 +502,16 @@
 
   url_request_context_factory_->InitializeOnUIThread(nullptr);
 
-  cast_browser_process_->SetConnectivityChecker(ConnectivityChecker::Create(
-      base::CreateSingleThreadTaskRunner({content::BrowserThread::IO}),
-      url_request_context_factory_->GetSystemGetter()));
-
   cast_browser_process_->SetBrowserContext(
       std::make_unique<CastBrowserContext>());
+
+  cast_browser_process_->SetConnectivityChecker(ConnectivityChecker::Create(
+      base::CreateSingleThreadTaskRunner({content::BrowserThread::IO}),
+      content::BrowserContext::GetDefaultStoragePartition(
+          cast_browser_process_->browser_context())
+          ->GetURLLoaderFactoryForBrowserProcessIOThread(),
+      content::GetNetworkConnectionTracker()));
+
   cast_browser_process_->SetMetricsServiceClient(
       std::make_unique<metrics::CastMetricsServiceClient>(
           cast_browser_process_->browser_client(),
diff --git a/chromecast/device/bluetooth/le/le_scan_manager_impl.cc b/chromecast/device/bluetooth/le/le_scan_manager_impl.cc
index fc2af72..b36c5b6 100644
--- a/chromecast/device/bluetooth/le/le_scan_manager_impl.cc
+++ b/chromecast/device/bluetooth/le/le_scan_manager_impl.cc
@@ -141,9 +141,25 @@
 void LeScanManagerImpl::SetScanParameters(int scan_interval_ms,
                                           int scan_window_ms) {
   MAKE_SURE_IO_THREAD(SetScanParameters, scan_interval_ms, scan_window_ms);
+  if (scan_handle_ids_.empty()) {
+    LOG(ERROR) << "Can't set scan parameters, no scan handle";
+    return;
+  }
+
+  // We could only set scan parameters when scan is paused.
+  if (!le_scanner_->StopScan()) {
+    LOG(ERROR) << "Failed to pause scanning before setting scan parameters";
+    return;
+  }
 
   if (!le_scanner_->SetScanParameters(scan_interval_ms, scan_window_ms)) {
     LOG(ERROR) << "Failed to set scan parameters";
+    return;
+  }
+
+  if (!le_scanner_->StartScan()) {
+    LOG(ERROR) << "Failed to restart scanning after setting scan parameters";
+    return;
   }
 
   LOG(INFO) << __func__ << " scan_interval: " << scan_interval_ms
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn
index 65fe625..7072580 100644
--- a/chromecast/media/cma/backend/BUILD.gn
+++ b/chromecast/media/cma/backend/BUILD.gn
@@ -10,8 +10,6 @@
 declare_args() {
   system_owns_volume =
       use_alsa && !enable_assistant && chromecast_branding != "google"
-
-  mixer_output = ""
 }
 
 cast_source_set("backend") {
@@ -106,9 +104,12 @@
 
   deps = [
     "//base",
-    "//chromecast/public/media",
     "//media",
   ]
+
+  public_deps = [
+    "//chromecast/public/media",
+  ]
 }
 
 cast_source_set("av_sync_dummy") {
@@ -144,19 +145,6 @@
   ]
 }
 
-cast_source_set("post_processor_factory") {
-  sources = [
-    "post_processor_factory.cc",
-    "post_processor_factory.h",
-  ]
-
-  deps = [
-    "//base",
-    "//chromecast/media/cma/backend/post_processors:post_processor_wrapper",
-    "//chromecast/public/media",
-  ]
-}
-
 cast_source_set("audio_resampler") {
   sources = [
     "audio_resampler.cc",
@@ -191,50 +179,6 @@
   cflags = [ "-ffast-math" ]
 }
 
-cast_source_set("mixer_control") {
-  sources = [
-    "mixer_control.h",
-  ]
-  deps = [
-    "//chromecast/public",
-  ]
-}
-
-cast_source_set("mixer_pipeline") {
-  sources = [
-    "audio_output_redirector_input.h",
-    "filter_group.cc",
-    "filter_group.h",
-    "mixer_input.cc",
-    "mixer_input.h",
-    "mixer_pipeline.cc",
-    "mixer_pipeline.h",
-    "post_processing_pipeline.h",
-    "post_processing_pipeline_impl.cc",
-    "post_processing_pipeline_impl.h",
-    "post_processing_pipeline_parser.cc",
-    "post_processing_pipeline_parser.h",
-  ]
-  deps = [
-    ":audio_buildflags",
-    ":audio_helpers",
-    ":audio_resampler",
-    ":cast_audio_json",
-    ":interleaved_channel_mixer",
-    ":post_processor_factory",
-    ":public",
-    "//base",
-    "//chromecast/base",
-    "//chromecast/media/base",
-    "//chromecast/media/cma/base",
-    "//chromecast/media/cma/decoder",
-    "//chromecast/public",
-    "//chromecast/public/media",
-    "//media",
-    "//media:shared_memory_support",
-  ]
-}
-
 cast_source_set("volume_map") {
   sources = [
     "volume_map.cc",
@@ -243,6 +187,7 @@
   deps = [
     ":cast_audio_json",
     "//base",
+    "//chromecast/public",
   ]
 }
 
@@ -250,106 +195,48 @@
   sources = [
     "audio_decoder_for_mixer.cc",
     "audio_decoder_for_mixer.h",
-    "audio_output_redirector.cc",
-    "audio_output_redirector.h",
-    "buffering_mixer_source.cc",
-    "buffering_mixer_source.h",
     "cast_media_shlib_mixer_audio.cc",
-    "direct_mixer_source.cc",
-    "direct_mixer_source.h",
-    "loopback_handler.cc",
-    "loopback_handler.h",
     "media_pipeline_backend_for_mixer.cc",
     "media_pipeline_backend_for_mixer.h",
-    "mixer_input_connection.cc",
-    "mixer_input_connection.h",
-    "mixer_service_receiver.cc",
-    "mixer_service_receiver.h",
-    "stream_mixer.cc",
-    "stream_mixer.h",
     "volume_control.cc",
   ]
 
   deps = [
     ":audio_buildflags",
     ":audio_helpers",
-    ":audio_resampler",
     ":cast_audio_json",
-    ":interleaved_channel_mixer",
-    ":mixer_control",
-    ":mixer_pipeline",
-    ":post_processor_factory",
     ":public",
     ":volume_map",
     "//base",
     "//chromecast/base",
-    "//chromecast/base:thread_health_checker",
-    "//chromecast/media/audio:libcast_external_audio_pipeline_1.0",
-    "//chromecast/media/audio/mixer_service:common",
-    "//chromecast/media/audio/mixer_service:proto",
-    "//chromecast/media/audio/mixer_service/receiver",
-    "//chromecast/media/base",
     "//chromecast/media/base:monotonic_clock",
+    "//chromecast/media/cma/backend/mixer",
     "//chromecast/media/cma/base",
     "//chromecast/media/cma/decoder",
-    "//chromecast/net:io_buffer_pool",
     "//chromecast/public",
     "//chromecast/public/media",
     "//media",
     "//media:shared_memory_support",
   ]
-
-  if (use_alsa) {
-    deps += [ "alsa:cma_backend_support" ]
-  } else if (is_fuchsia) {
-    deps += [ "fuchsia:cma_backend_support" ]
-  } else {
-    # If enable_video_with_mixed_audio && !use_alsa, the platform needs to
-    # provide its own mixer output.
-    if (!enable_video_with_mixed_audio) {
-      sources += [ "mixer_output_stream_dummy.cc" ]
-    } else {
-      assert("$mixer_output" != "")
-      deps += [ "$mixer_output" ]
-    }
-  }
 }
 
 test("cast_audio_backend_unittests") {
   testonly = true
   sources = [
     "audio_fader_unittest.cc",
-    "filter_group_unittest.cc",
     "interleaved_channel_mixer_unittest.cc",
-    "mock_mixer_source.cc",
-    "mock_mixer_source.h",
-    "mock_post_processor_factory.cc",
-    "mock_post_processor_factory.h",
-    "mock_redirected_audio_output.cc",
-    "mock_redirected_audio_output.h",
-    "stream_mixer_external_audio_pipeline_unittest.cc",
-    "stream_mixer_unittest.cc",
     "volume_map_unittest.cc",
   ]
 
   deps = [
     ":audio_helpers",
-    ":av_sync_dummy",
     ":cast_audio_json",
-    ":for_mixer_audio",
     ":interleaved_channel_mixer",
-    ":mixer_pipeline",
-    ":null_video",
-    ":public",
     ":volume_map",
     "//base",
     "//base/test:run_all_unittests",
-    "//chromecast/media/audio:fake_external_audio_pipeline",
-    "//chromecast/media/cma/backend/post_processors:unittests",
-    "//chromecast/public",
-    "//chromecast/public/media",
+    "//chromecast/media/cma/backend/mixer:unittests",
     "//media",
-    "//media:shared_memory_support",
     "//testing/gmock",
     "//testing/gtest",
   ]
diff --git a/chromecast/media/cma/backend/alsa/BUILD.gn b/chromecast/media/cma/backend/alsa/BUILD.gn
index 0daf87d2..a7ae5fb 100644
--- a/chromecast/media/cma/backend/alsa/BUILD.gn
+++ b/chromecast/media/cma/backend/alsa/BUILD.gn
@@ -16,6 +16,7 @@
   ]
 
   deps = [
+    ":volume_control",
     "//base",
     "//chromecast/base",
     "//chromecast/media/cma/backend:audio_codec_support",
@@ -28,12 +29,39 @@
   ]
 }
 
-cast_source_set("cma_backend_support") {
+cast_source_set("alsa_wrapper") {
+  sources = [
+    "alsa_wrapper.cc",
+    "alsa_wrapper.h",
+  ]
+
+  libs = [ "asound" ]
+
+  deps = [
+    "//base",
+    "//chromecast/media/cma/backend:audio_buildflags",
+    "//media",
+  ]
+}
+
+cast_source_set("volume_control") {
   sources = [
     "alsa_volume_control.cc",
     "alsa_volume_control.h",
-    "alsa_wrapper.cc",
-    "alsa_wrapper.h",
+  ]
+
+  libs = [ "asound" ]
+
+  deps = [
+    "//base",
+    "//chromecast/base:chromecast_switches",
+    "//chromecast/media/cma/backend:public",
+    "//media",
+  ]
+}
+
+cast_source_set("mixer_output") {
+  sources = [
     "mixer_output_stream_alsa.cc",
     "mixer_output_stream_alsa.h",
   ]
@@ -41,13 +69,9 @@
   libs = [ "asound" ]
 
   deps = [
+    ":alsa_wrapper",
     "//base",
-    "//chromecast/base",
-    "//chromecast/media/base",
-    "//chromecast/media/cma/backend:audio_buildflags",
-    "//chromecast/media/cma/backend:public",
-    "//chromecast/media/cma/base",
-    "//chromecast/media/cma/decoder",
+    "//chromecast/base:chromecast_switches",
     "//chromecast/public/media",
     "//media",
   ]
diff --git a/chromecast/media/cma/backend/audio_decoder_for_mixer.h b/chromecast/media/cma/backend/audio_decoder_for_mixer.h
index 4adea3c..72482313 100644
--- a/chromecast/media/cma/backend/audio_decoder_for_mixer.h
+++ b/chromecast/media/cma/backend/audio_decoder_for_mixer.h
@@ -11,7 +11,7 @@
 #include "base/bind.h"
 #include "base/containers/circular_deque.h"
 #include "base/location.h"
-#include "chromecast/media/cma/backend/buffering_mixer_source.h"
+#include "chromecast/media/cma/backend/mixer/buffering_mixer_source.h"
 #include "chromecast/media/cma/decoder/cast_audio_decoder.h"
 #include "chromecast/public/media/decoder_config.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
diff --git a/chromecast/media/cma/backend/cast_media_shlib_mixer_audio.cc b/chromecast/media/cma/backend/cast_media_shlib_mixer_audio.cc
index dd6dd5f7..a191376 100644
--- a/chromecast/media/cma/backend/cast_media_shlib_mixer_audio.cc
+++ b/chromecast/media/cma/backend/cast_media_shlib_mixer_audio.cc
@@ -9,7 +9,7 @@
 #include <string>
 #include <utility>
 
-#include "chromecast/media/cma/backend/stream_mixer.h"
+#include "chromecast/media/cma/backend/mixer/stream_mixer.h"
 
 namespace chromecast {
 namespace media {
diff --git a/chromecast/media/cma/backend/cplay/BUILD.gn b/chromecast/media/cma/backend/cplay/BUILD.gn
index de9c6c4..0d9a938 100644
--- a/chromecast/media/cma/backend/cplay/BUILD.gn
+++ b/chromecast/media/cma/backend/cplay/BUILD.gn
@@ -10,9 +10,9 @@
   deps = [
     "//base",
     "//chromecast/media/cma/backend:cast_audio_json",
-    "//chromecast/media/cma/backend:mixer_pipeline",
     "//chromecast/media/cma/backend:public",
     "//chromecast/media/cma/backend:volume_map",
+    "//chromecast/media/cma/backend/mixer",
     "//chromecast/public",
     "//chromecast/public/media",
     "//media",
diff --git a/chromecast/media/cma/backend/fuchsia/BUILD.gn b/chromecast/media/cma/backend/fuchsia/BUILD.gn
index 040b05a..17b9ffdb 100644
--- a/chromecast/media/cma/backend/fuchsia/BUILD.gn
+++ b/chromecast/media/cma/backend/fuchsia/BUILD.gn
@@ -14,6 +14,7 @@
   ]
 
   deps = [
+    ":volume_control",
     "//base",
     "//chromecast/base",
     "//chromecast/media/cma/backend:audio_codec_support",
@@ -26,9 +27,20 @@
   ]
 }
 
-cast_source_set("cma_backend_support") {
+cast_source_set("volume_control") {
   sources = [
     "fuchsia_volume_control.cc",
+    "fuchsia_volume_control.h",
+  ]
+
+  deps = [
+    "//base",
+    "//chromecast/media/cma/backend:public",
+  ]
+}
+
+cast_source_set("mixer_output") {
+  sources = [
     "mixer_output_stream_fuchsia.cc",
     "mixer_output_stream_fuchsia.h",
   ]
@@ -36,8 +48,6 @@
   deps = [
     "//base",
     "//chromecast/base",
-    "//chromecast/media/cma/backend:public",
-    "//chromecast/public",
     "//chromecast/public/media",
     "//media",
     "//third_party/fuchsia-sdk/sdk:media",
@@ -54,7 +64,7 @@
   configs += [ "//chromecast/public:public_config" ]
 
   deps = [
-    ":cma_backend_support",
+    ":mixer_output",
     "//base",
     "//base/test:test_support",
     "//testing/gtest",
diff --git a/chromecast/media/cma/backend/fuchsia/cast_media_shlib_fuchsia.cc b/chromecast/media/cma/backend/fuchsia/cast_media_shlib_fuchsia.cc
index a518568..60ca701 100644
--- a/chromecast/media/cma/backend/fuchsia/cast_media_shlib_fuchsia.cc
+++ b/chromecast/media/cma/backend/fuchsia/cast_media_shlib_fuchsia.cc
@@ -5,7 +5,6 @@
 #include "chromecast/public/cast_media_shlib.h"
 
 #include "chromecast/media/cma/backend/media_pipeline_backend_for_mixer.h"
-#include "chromecast/media/cma/backend/stream_mixer.h"
 #include "chromecast/public/graphics_types.h"
 #include "chromecast/public/video_plane.h"
 #include "media/base/media.h"
@@ -75,19 +74,5 @@
   return false;
 }
 
-void CastMediaShlib::AddLoopbackAudioObserver(LoopbackAudioObserver* observer) {
-  StreamMixer::Get()->AddLoopbackAudioObserver(observer);
-}
-
-void CastMediaShlib::RemoveLoopbackAudioObserver(
-    LoopbackAudioObserver* observer) {
-  StreamMixer::Get()->RemoveLoopbackAudioObserver(observer);
-}
-
-void CastMediaShlib::SetPostProcessorConfig(const std::string& name,
-                                            const std::string& config) {
-  StreamMixer::Get()->SetPostProcessorConfig(name, config);
-}
-
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cma/backend/mixer/BUILD.gn b/chromecast/media/cma/backend/mixer/BUILD.gn
new file mode 100644
index 0000000..18de732
--- /dev/null
+++ b/chromecast/media/cma/backend/mixer/BUILD.gn
@@ -0,0 +1,132 @@
+# 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.
+
+import("//build/config/chromecast_build.gni")
+import("//chromecast/chromecast.gni")
+import("//media/media_options.gni")
+
+declare_args() {
+  mixer_output = ""
+}
+
+cast_source_set("mixer_control") {
+  sources = [
+    "mixer_control.h",
+  ]
+  deps = [
+    "//chromecast/public",
+  ]
+}
+
+cast_source_set("post_processor_paths") {
+  sources = [
+    "post_processor_paths.cc",
+    "post_processor_paths.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
+cast_source_set("mixer") {
+  sources = [
+    "audio_output_redirector.cc",
+    "audio_output_redirector.h",
+    "audio_output_redirector_input.h",
+    "buffering_mixer_source.cc",
+    "buffering_mixer_source.h",
+    "direct_mixer_source.cc",
+    "direct_mixer_source.h",
+    "filter_group.cc",
+    "filter_group.h",
+    "loopback_handler.cc",
+    "loopback_handler.h",
+    "mixer_input.cc",
+    "mixer_input.h",
+    "mixer_input_connection.cc",
+    "mixer_input_connection.h",
+    "mixer_pipeline.cc",
+    "mixer_pipeline.h",
+    "mixer_service_receiver.cc",
+    "mixer_service_receiver.h",
+    "post_processing_pipeline.h",
+    "post_processing_pipeline_impl.cc",
+    "post_processing_pipeline_impl.h",
+    "post_processing_pipeline_parser.cc",
+    "post_processing_pipeline_parser.h",
+    "post_processor_factory.cc",
+    "post_processor_factory.h",
+    "stream_mixer.cc",
+    "stream_mixer.h",
+  ]
+
+  deps = [
+    ":mixer_control",
+    ":post_processor_paths",
+    "//base",
+    "//chromecast/base",
+    "//chromecast/base:chromecast_switches",
+    "//chromecast/base:thread_health_checker",
+    "//chromecast/media/audio:libcast_external_audio_pipeline_1.0",
+    "//chromecast/media/audio/mixer_service:common",
+    "//chromecast/media/audio/mixer_service:proto",
+    "//chromecast/media/audio/mixer_service/receiver",
+    "//chromecast/media/base",
+    "//chromecast/media/cma/backend:audio_helpers",
+    "//chromecast/media/cma/backend:audio_resampler",
+    "//chromecast/media/cma/backend:cast_audio_json",
+    "//chromecast/media/cma/backend:interleaved_channel_mixer",
+    "//chromecast/media/cma/backend:volume_map",
+    "//chromecast/media/cma/backend/mixer/post_processors:post_processor_wrapper",
+    "//chromecast/media/cma/base",
+    "//chromecast/net:io_buffer_pool",
+    "//chromecast/public",
+    "//chromecast/public/media",
+    "//media",
+    "//media:shared_memory_support",
+  ]
+
+  if (use_alsa) {
+    deps += [ "//chromecast/media/cma/backend/alsa:mixer_output" ]
+  } else if (is_fuchsia) {
+    deps += [ "//chromecast/media/cma/backend/fuchsia:mixer_output" ]
+  } else {
+    # If enable_video_with_mixed_audio && !use_alsa, the platform needs to
+    # provide its own mixer output.
+    if (!enable_video_with_mixed_audio) {
+      sources += [ "mixer_output_stream_dummy.cc" ]
+    } else {
+      assert("$mixer_output" != "")
+      deps += [ "$mixer_output" ]
+    }
+  }
+}
+
+cast_source_set("unittests") {
+  testonly = true
+  sources = [
+    "filter_group_unittest.cc",
+    "mock_mixer_source.cc",
+    "mock_mixer_source.h",
+    "mock_post_processor_factory.cc",
+    "mock_post_processor_factory.h",
+    "mock_redirected_audio_output.cc",
+    "mock_redirected_audio_output.h",
+    "stream_mixer_external_audio_pipeline_unittest.cc",
+    "stream_mixer_unittest.cc",
+  ]
+
+  deps = [
+    ":mixer",
+    "//base",
+    "//chromecast/media/audio:fake_external_audio_pipeline",
+    "//chromecast/media/cma/backend/mixer/post_processors:unittests",
+    "//chromecast/public",
+    "//chromecast/public/media",
+    "//media",
+    "//media:shared_memory_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/chromecast/media/cma/backend/audio_output_redirector.cc b/chromecast/media/cma/backend/mixer/audio_output_redirector.cc
similarity index 97%
rename from chromecast/media/cma/backend/audio_output_redirector.cc
rename to chromecast/media/cma/backend/mixer/audio_output_redirector.cc
index 9648b69f..6339958 100644
--- a/chromecast/media/cma/backend/audio_output_redirector.cc
+++ b/chromecast/media/cma/backend/mixer/audio_output_redirector.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 "chromecast/media/cma/backend/audio_output_redirector.h"
+#include "chromecast/media/cma/backend/mixer/audio_output_redirector.h"
 
 #include <algorithm>
 #include <utility>
@@ -12,9 +12,9 @@
 #include "base/strings/pattern.h"
 #include "base/values.h"
 #include "chromecast/media/cma/backend/audio_fader.h"
-#include "chromecast/media/cma/backend/audio_output_redirector_input.h"
-#include "chromecast/media/cma/backend/mixer_input.h"
-#include "chromecast/media/cma/backend/stream_mixer.h"
+#include "chromecast/media/cma/backend/mixer/audio_output_redirector_input.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input.h"
+#include "chromecast/media/cma/backend/mixer/stream_mixer.h"
 #include "chromecast/public/cast_media_shlib.h"
 #include "media/base/audio_bus.h"
 #include "media/base/audio_timestamp_helper.h"
diff --git a/chromecast/media/cma/backend/audio_output_redirector.h b/chromecast/media/cma/backend/mixer/audio_output_redirector.h
similarity index 94%
rename from chromecast/media/cma/backend/audio_output_redirector.h
rename to chromecast/media/cma/backend/mixer/audio_output_redirector.h
index 46a7173..d1bd22e 100644
--- a/chromecast/media/cma/backend/audio_output_redirector.h
+++ b/chromecast/media/cma/backend/mixer/audio_output_redirector.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 CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_OUTPUT_REDIRECTOR_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_OUTPUT_REDIRECTOR_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_AUDIO_OUTPUT_REDIRECTOR_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_AUDIO_OUTPUT_REDIRECTOR_H_
 
 #include <cstdint>
 #include <memory>
@@ -116,4 +116,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_OUTPUT_REDIRECTOR_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_AUDIO_OUTPUT_REDIRECTOR_H_
diff --git a/chromecast/media/cma/backend/audio_output_redirector_input.h b/chromecast/media/cma/backend/mixer/audio_output_redirector_input.h
similarity index 84%
rename from chromecast/media/cma/backend/audio_output_redirector_input.h
rename to chromecast/media/cma/backend/mixer/audio_output_redirector_input.h
index 914ae8d2..34522d0 100644
--- a/chromecast/media/cma/backend/audio_output_redirector_input.h
+++ b/chromecast/media/cma/backend/mixer/audio_output_redirector_input.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 CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_OUTPUT_REDIRECTOR_INPUT_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_OUTPUT_REDIRECTOR_INPUT_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_AUDIO_OUTPUT_REDIRECTOR_INPUT_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_AUDIO_OUTPUT_REDIRECTOR_INPUT_H_
 
 namespace media {
 class AudioBus;
@@ -41,4 +41,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_OUTPUT_REDIRECTOR_INPUT_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_AUDIO_OUTPUT_REDIRECTOR_INPUT_H_
diff --git a/chromecast/media/cma/backend/buffering_mixer_source.cc b/chromecast/media/cma/backend/mixer/buffering_mixer_source.cc
similarity index 99%
rename from chromecast/media/cma/backend/buffering_mixer_source.cc
rename to chromecast/media/cma/backend/mixer/buffering_mixer_source.cc
index c7e5da6..2216204 100644
--- a/chromecast/media/cma/backend/buffering_mixer_source.cc
+++ b/chromecast/media/cma/backend/mixer/buffering_mixer_source.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 "chromecast/media/cma/backend/buffering_mixer_source.h"
+#include "chromecast/media/cma/backend/mixer/buffering_mixer_source.h"
 
 #include <stdint.h>
 #include <string.h>
@@ -18,7 +18,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chromecast/base/chromecast_switches.h"
-#include "chromecast/media/cma/backend/stream_mixer.h"
+#include "chromecast/media/cma/backend/mixer/stream_mixer.h"
 #include "chromecast/media/cma/base/decoder_buffer_adapter.h"
 #include "chromecast/media/cma/base/decoder_buffer_base.h"
 #include "media/audio/audio_device_description.h"
diff --git a/chromecast/media/cma/backend/buffering_mixer_source.h b/chromecast/media/cma/backend/mixer/buffering_mixer_source.h
similarity index 96%
rename from chromecast/media/cma/backend/buffering_mixer_source.h
rename to chromecast/media/cma/backend/mixer/buffering_mixer_source.h
index bddbaa53..6387211 100644
--- a/chromecast/media/cma/backend/buffering_mixer_source.h
+++ b/chromecast/media/cma/backend/mixer/buffering_mixer_source.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 CHROMECAST_MEDIA_CMA_BACKEND_BUFFERING_MIXER_SOURCE_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_BUFFERING_MIXER_SOURCE_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_BUFFERING_MIXER_SOURCE_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_BUFFERING_MIXER_SOURCE_H_
 
 #include <string>
 #include <vector>
@@ -17,7 +17,7 @@
 #include "base/thread_annotations.h"
 #include "chromecast/media/cma/backend/audio_fader.h"
 #include "chromecast/media/cma/backend/audio_resampler.h"
-#include "chromecast/media/cma/backend/mixer_input.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/volume_control.h"
 
@@ -232,4 +232,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_BUFFERING_MIXER_SOURCE_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_BUFFERING_MIXER_SOURCE_H_
diff --git a/chromecast/media/cma/backend/direct_mixer_source.cc b/chromecast/media/cma/backend/mixer/direct_mixer_source.cc
similarity index 96%
rename from chromecast/media/cma/backend/direct_mixer_source.cc
rename to chromecast/media/cma/backend/mixer/direct_mixer_source.cc
index 817a562..23007e3 100644
--- a/chromecast/media/cma/backend/direct_mixer_source.cc
+++ b/chromecast/media/cma/backend/mixer/direct_mixer_source.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/backend/direct_mixer_source.h"
+#include "chromecast/media/cma/backend/mixer/direct_mixer_source.h"
 
 #include "base/logging.h"
-#include "chromecast/media/cma/backend/stream_mixer.h"
+#include "chromecast/media/cma/backend/mixer/stream_mixer.h"
 #include "chromecast/public/media/direct_audio_source.h"
 #include "chromecast/public/media/media_pipeline_device_params.h"
 #include "media/base/audio_bus.h"
diff --git a/chromecast/media/cma/backend/direct_mixer_source.h b/chromecast/media/cma/backend/mixer/direct_mixer_source.h
similarity index 90%
rename from chromecast/media/cma/backend/direct_mixer_source.h
rename to chromecast/media/cma/backend/mixer/direct_mixer_source.h
index 1fa8d09..fd44896 100644
--- a/chromecast/media/cma/backend/direct_mixer_source.h
+++ b/chromecast/media/cma/backend/mixer/direct_mixer_source.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_DIRECT_MIXER_SOURCE_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_DIRECT_MIXER_SOURCE_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_DIRECT_MIXER_SOURCE_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_DIRECT_MIXER_SOURCE_H_
 
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
-#include "chromecast/media/cma/backend/mixer_input.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/volume_control.h"
 
@@ -83,4 +83,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_DIRECT_MIXER_SOURCE_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_DIRECT_MIXER_SOURCE_H_
diff --git a/chromecast/media/cma/backend/filter_group.cc b/chromecast/media/cma/backend/mixer/filter_group.cc
similarity index 97%
rename from chromecast/media/cma/backend/filter_group.cc
rename to chromecast/media/cma/backend/mixer/filter_group.cc
index 3a0659d..46a5dd4 100644
--- a/chromecast/media/cma/backend/filter_group.cc
+++ b/chromecast/media/cma/backend/mixer/filter_group.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 "chromecast/media/cma/backend/filter_group.h"
+#include "chromecast/media/cma/backend/mixer/filter_group.h"
 
 #include <algorithm>
 
@@ -10,8 +10,8 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chromecast/media/cma/backend/interleaved_channel_mixer.h"
-#include "chromecast/media/cma/backend/mixer_input.h"
-#include "chromecast/media/cma/backend/post_processing_pipeline.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input.h"
+#include "chromecast/media/cma/backend/mixer/post_processing_pipeline.h"
 #include "media/base/audio_bus.h"
 #include "media/base/audio_sample_types.h"
 #include "media/base/vector_math.h"
diff --git a/chromecast/media/cma/backend/filter_group.h b/chromecast/media/cma/backend/mixer/filter_group.h
similarity index 96%
rename from chromecast/media/cma/backend/filter_group.h
rename to chromecast/media/cma/backend/mixer/filter_group.h
index 395e1b8..2009bd6 100644
--- a/chromecast/media/cma/backend/filter_group.h
+++ b/chromecast/media/cma/backend/mixer/filter_group.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 CHROMECAST_MEDIA_CMA_BACKEND_FILTER_GROUP_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_FILTER_GROUP_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_FILTER_GROUP_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_FILTER_GROUP_H_
 
 #include <stdint.h>
 
@@ -162,4 +162,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_FILTER_GROUP_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_FILTER_GROUP_H_
diff --git a/chromecast/media/cma/backend/filter_group_unittest.cc b/chromecast/media/cma/backend/mixer/filter_group_unittest.cc
similarity index 96%
rename from chromecast/media/cma/backend/filter_group_unittest.cc
rename to chromecast/media/cma/backend/mixer/filter_group_unittest.cc
index 3966f7b..fb9daf4 100644
--- a/chromecast/media/cma/backend/filter_group_unittest.cc
+++ b/chromecast/media/cma/backend/mixer/filter_group_unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/backend/filter_group.h"
+#include "chromecast/media/cma/backend/mixer/filter_group.h"
 
 #include "base/containers/flat_set.h"
 #include "base/memory/ptr_util.h"
-#include "chromecast/media/cma/backend/mixer_input.h"
-#include "chromecast/media/cma/backend/mock_mixer_source.h"
-#include "chromecast/media/cma/backend/post_processing_pipeline.h"
-#include "chromecast/media/cma/backend/stream_mixer.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input.h"
+#include "chromecast/media/cma/backend/mixer/mock_mixer_source.h"
+#include "chromecast/media/cma/backend/mixer/post_processing_pipeline.h"
+#include "chromecast/media/cma/backend/mixer/stream_mixer.h"
 #include "chromecast/public/media/audio_post_processor2_shlib.h"
 #include "chromecast/public/volume_control.h"
 #include "media/base/audio_bus.h"
@@ -39,7 +39,7 @@
   MockPostProcessingPipeline()
       : MockPostProcessingPipeline(kNumInputChannels) {}
 
-  MockPostProcessingPipeline(int num_output_channels)
+  explicit MockPostProcessingPipeline(int num_output_channels)
       : num_output_channels_(num_output_channels) {
     ON_CALL(*this, ProcessFrames(_, _, _, _))
         .WillByDefault(
diff --git a/chromecast/media/cma/backend/loopback_handler.cc b/chromecast/media/cma/backend/mixer/loopback_handler.cc
similarity index 98%
rename from chromecast/media/cma/backend/loopback_handler.cc
rename to chromecast/media/cma/backend/mixer/loopback_handler.cc
index 8513058..bc60460 100644
--- a/chromecast/media/cma/backend/loopback_handler.cc
+++ b/chromecast/media/cma/backend/mixer/loopback_handler.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/backend/loopback_handler.h"
+#include "chromecast/media/cma/backend/mixer/loopback_handler.h"
 
 #include <algorithm>
 #include <utility>
@@ -31,7 +31,8 @@
 class LoopbackHandlerImpl : public LoopbackHandler,
                             public CastMediaShlib::LoopbackAudioObserver {
  public:
-  LoopbackHandlerImpl(scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+  explicit LoopbackHandlerImpl(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner)
       : external_audio_pipeline_supported_(
             ExternalAudioPipelineShlib::IsSupported()),
         task_signal_(&lock_) {
diff --git a/chromecast/media/cma/backend/loopback_handler.h b/chromecast/media/cma/backend/mixer/loopback_handler.h
similarity index 87%
rename from chromecast/media/cma/backend/loopback_handler.h
rename to chromecast/media/cma/backend/mixer/loopback_handler.h
index 807c89c..9206e17 100644
--- a/chromecast/media/cma/backend/loopback_handler.h
+++ b/chromecast/media/cma/backend/mixer/loopback_handler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_LOOPBACK_HANDLER_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_LOOPBACK_HANDLER_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_LOOPBACK_HANDLER_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_LOOPBACK_HANDLER_H_
 
 #include <cstdint>
 #include <memory>
@@ -52,4 +52,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_LOOPBACK_HANDLER_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_LOOPBACK_HANDLER_H_
diff --git a/chromecast/media/cma/backend/mixer_control.h b/chromecast/media/cma/backend/mixer/mixer_control.h
similarity index 84%
rename from chromecast/media/cma/backend/mixer_control.h
rename to chromecast/media/cma/backend/mixer/mixer_control.h
index 83a70a4..3a8e600 100644
--- a/chromecast/media/cma/backend/mixer_control.h
+++ b/chromecast/media/cma/backend/mixer/mixer_control.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 CHROMECAST_MEDIA_CMA_BACKEND_MIXER_CONTROL_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_CONTROL_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_CONTROL_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_CONTROL_H_
 
 #include "chromecast/public/chromecast_export.h"
 
@@ -31,4 +31,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_CONTROL_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_CONTROL_H_
diff --git a/chromecast/media/cma/backend/mixer_input.cc b/chromecast/media/cma/backend/mixer/mixer_input.cc
similarity index 98%
rename from chromecast/media/cma/backend/mixer_input.cc
rename to chromecast/media/cma/backend/mixer/mixer_input.cc
index d9b6867..355a97f7 100644
--- a/chromecast/media/cma/backend/mixer_input.cc
+++ b/chromecast/media/cma/backend/mixer/mixer_input.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 "chromecast/media/cma/backend/mixer_input.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input.h"
 
 #include <stdint.h>
 
@@ -15,8 +15,8 @@
 #include "base/logging.h"
 #include "base/numerics/ranges.h"
 #include "chromecast/media/cma/backend/audio_fader.h"
-#include "chromecast/media/cma/backend/audio_output_redirector_input.h"
-#include "chromecast/media/cma/backend/filter_group.h"
+#include "chromecast/media/cma/backend/mixer/audio_output_redirector_input.h"
+#include "chromecast/media/cma/backend/mixer/filter_group.h"
 #include "media/base/audio_bus.h"
 #include "media/base/audio_timestamp_helper.h"
 #include "media/base/channel_mixer.h"
diff --git a/chromecast/media/cma/backend/mixer_input.h b/chromecast/media/cma/backend/mixer/mixer_input.h
similarity index 96%
rename from chromecast/media/cma/backend/mixer_input.h
rename to chromecast/media/cma/backend/mixer/mixer_input.h
index 69e3eb3..7c9d16d 100644
--- a/chromecast/media/cma/backend/mixer_input.h
+++ b/chromecast/media/cma/backend/mixer/mixer_input.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 CHROMECAST_MEDIA_CMA_BACKEND_MIXER_INPUT_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_INPUT_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_INPUT_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_INPUT_H_
 
 #include <memory>
 #include <string>
@@ -84,8 +84,7 @@
     virtual ~Source() = default;
   };
 
-  MixerInput(Source* source,
-             FilterGroup* filter_group);
+  MixerInput(Source* source, FilterGroup* filter_group);
   ~MixerInput();
 
   void SetFilterGroup(FilterGroup* filter_group);
@@ -186,4 +185,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_INPUT_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_INPUT_H_
diff --git a/chromecast/media/cma/backend/mixer_input_connection.cc b/chromecast/media/cma/backend/mixer/mixer_input_connection.cc
similarity index 99%
rename from chromecast/media/cma/backend/mixer_input_connection.cc
rename to chromecast/media/cma/backend/mixer/mixer_input_connection.cc
index 20fd1ba..6850477 100644
--- a/chromecast/media/cma/backend/mixer_input_connection.cc
+++ b/chromecast/media/cma/backend/mixer/mixer_input_connection.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 "chromecast/media/cma/backend/mixer_input_connection.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input_connection.h"
 
 #include <stdint.h>
 #include <string.h>
@@ -21,7 +21,7 @@
 #include "chromecast/base/chromecast_switches.h"
 #include "chromecast/media/audio/mixer_service/conversions.h"
 #include "chromecast/media/audio/mixer_service/mixer_service.pb.h"
-#include "chromecast/media/cma/backend/stream_mixer.h"
+#include "chromecast/media/cma/backend/mixer/stream_mixer.h"
 #include "chromecast/net/io_buffer_pool.h"
 #include "media/audio/audio_device_description.h"
 #include "media/base/audio_bus.h"
diff --git a/chromecast/media/cma/backend/mixer_input_connection.h b/chromecast/media/cma/backend/mixer/mixer_input_connection.h
similarity index 95%
rename from chromecast/media/cma/backend/mixer_input_connection.h
rename to chromecast/media/cma/backend/mixer/mixer_input_connection.h
index d069e2f..51e87bc 100644
--- a/chromecast/media/cma/backend/mixer_input_connection.h
+++ b/chromecast/media/cma/backend/mixer/mixer_input_connection.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 CHROMECAST_MEDIA_CMA_BACKEND_MIXER_INPUT_CONNECTION_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_INPUT_CONNECTION_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_INPUT_CONNECTION_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_INPUT_CONNECTION_H_
 
 #include <memory>
 #include <string>
@@ -18,7 +18,7 @@
 #include "base/timer/timer.h"
 #include "chromecast/media/audio/mixer_service/mixer_socket.h"
 #include "chromecast/media/cma/backend/audio_fader.h"
-#include "chromecast/media/cma/backend/mixer_input.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "chromecast/public/volume_control.h"
 
@@ -187,4 +187,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_INPUT_CONNECTION_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_INPUT_CONNECTION_H_
diff --git a/chromecast/media/cma/backend/mixer_output_stream_dummy.cc b/chromecast/media/cma/backend/mixer/mixer_output_stream_dummy.cc
similarity index 81%
rename from chromecast/media/cma/backend/mixer_output_stream_dummy.cc
rename to chromecast/media/cma/backend/mixer/mixer_output_stream_dummy.cc
index 32c21d7..98f1bdc 100644
--- a/chromecast/media/cma/backend/mixer_output_stream_dummy.cc
+++ b/chromecast/media/cma/backend/mixer/mixer_output_stream_dummy.cc
@@ -5,7 +5,6 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "chromecast/media/cma/backend/system_volume_control.h"
 #include "chromecast/public/media/mixer_output_stream.h"
 
 namespace chromecast {
@@ -47,13 +46,5 @@
   return std::make_unique<MixerOutputStreamDummy>();
 }
 
-// static
-std::unique_ptr<SystemVolumeControl> SystemVolumeControl::Create(
-    Delegate* delegate) {
-  // No tests currently actually call this, so we don't need a real dummy
-  // implementation here.
-  return nullptr;
-}
-
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cma/backend/mixer_pipeline.cc b/chromecast/media/cma/backend/mixer/mixer_pipeline.cc
similarity index 96%
rename from chromecast/media/cma/backend/mixer_pipeline.cc
rename to chromecast/media/cma/backend/mixer/mixer_pipeline.cc
index 72687a1..7a702e7 100644
--- a/chromecast/media/cma/backend/mixer_pipeline.cc
+++ b/chromecast/media/cma/backend/mixer/mixer_pipeline.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 "chromecast/media/cma/backend/mixer_pipeline.h"
+#include "chromecast/media/cma/backend/mixer/mixer_pipeline.h"
 
 #include <algorithm>
 #include <utility>
@@ -10,9 +10,9 @@
 #include "base/containers/flat_set.h"
 #include "base/logging.h"
 #include "chromecast/media/base/audio_device_ids.h"
-#include "chromecast/media/cma/backend/filter_group.h"
-#include "chromecast/media/cma/backend/post_processing_pipeline_impl.h"
-#include "chromecast/media/cma/backend/post_processing_pipeline_parser.h"
+#include "chromecast/media/cma/backend/mixer/filter_group.h"
+#include "chromecast/media/cma/backend/mixer/post_processing_pipeline_impl.h"
+#include "chromecast/media/cma/backend/mixer/post_processing_pipeline_parser.h"
 #include "chromecast/public/media/audio_post_processor2_shlib.h"
 #include "media/audio/audio_device_description.h"
 
diff --git a/chromecast/media/cma/backend/mixer_pipeline.h b/chromecast/media/cma/backend/mixer/mixer_pipeline.h
similarity index 95%
rename from chromecast/media/cma/backend/mixer_pipeline.h
rename to chromecast/media/cma/backend/mixer/mixer_pipeline.h
index 84cfc35..34482ec 100644
--- a/chromecast/media/cma/backend/mixer_pipeline.h
+++ b/chromecast/media/cma/backend/mixer/mixer_pipeline.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 CHROMECAST_MEDIA_CMA_BACKEND_MIXER_PIPELINE_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_PIPELINE_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_PIPELINE_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_PIPELINE_H_
 
 #include <cstdint>
 #include <memory>
@@ -107,4 +107,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_PIPELINE_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_PIPELINE_H_
diff --git a/chromecast/media/cma/backend/mixer_service_receiver.cc b/chromecast/media/cma/backend/mixer/mixer_service_receiver.cc
similarity index 91%
rename from chromecast/media/cma/backend/mixer_service_receiver.cc
rename to chromecast/media/cma/backend/mixer/mixer_service_receiver.cc
index 4c713ed..65d6c68 100644
--- a/chromecast/media/cma/backend/mixer_service_receiver.cc
+++ b/chromecast/media/cma/backend/mixer/mixer_service_receiver.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/backend/mixer_service_receiver.h"
+#include "chromecast/media/cma/backend/mixer/mixer_service_receiver.h"
 
 #include <utility>
 
 #include "base/logging.h"
 #include "chromecast/media/audio/mixer_service/mixer_service.pb.h"
 #include "chromecast/media/audio/mixer_service/mixer_socket.h"
-#include "chromecast/media/cma/backend/mixer_input_connection.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input_connection.h"
 
 namespace chromecast {
 namespace media {
diff --git a/chromecast/media/cma/backend/mixer_service_receiver.h b/chromecast/media/cma/backend/mixer/mixer_service_receiver.h
similarity index 86%
rename from chromecast/media/cma/backend/mixer_service_receiver.h
rename to chromecast/media/cma/backend/mixer/mixer_service_receiver.h
index e249f188..239b8f58 100644
--- a/chromecast/media/cma/backend/mixer_service_receiver.h
+++ b/chromecast/media/cma/backend/mixer/mixer_service_receiver.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 CHROMECAST_MEDIA_CMA_BACKEND_MIXER_SERVICE_RECEIVER_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_SERVICE_RECEIVER_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_SERVICE_RECEIVER_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_SERVICE_RECEIVER_H_
 
 #include <memory>
 
@@ -46,4 +46,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_SERVICE_RECEIVER_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_SERVICE_RECEIVER_H_
diff --git a/chromecast/media/cma/backend/mock_mixer_source.cc b/chromecast/media/cma/backend/mixer/mock_mixer_source.cc
similarity index 94%
rename from chromecast/media/cma/backend/mock_mixer_source.cc
rename to chromecast/media/cma/backend/mixer/mock_mixer_source.cc
index 491f580..6eb00d3 100644
--- a/chromecast/media/cma/backend/mock_mixer_source.cc
+++ b/chromecast/media/cma/backend/mixer/mock_mixer_source.cc
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/backend/mock_mixer_source.h"
+#include "chromecast/media/cma/backend/mixer/mock_mixer_source.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/logging.h"
diff --git a/chromecast/media/cma/backend/mock_mixer_source.h b/chromecast/media/cma/backend/mixer/mock_mixer_source.h
similarity index 90%
rename from chromecast/media/cma/backend/mock_mixer_source.h
rename to chromecast/media/cma/backend/mixer/mock_mixer_source.h
index 75ebbb4..ef7ed7cb 100644
--- a/chromecast/media/cma/backend/mock_mixer_source.h
+++ b/chromecast/media/cma/backend/mixer/mock_mixer_source.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MOCK_MIXER_SOURCE_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MOCK_MIXER_SOURCE_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MOCK_MIXER_SOURCE_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MOCK_MIXER_SOURCE_H_
 
 #include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "chromecast/media/cma/backend/mixer_input.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input.h"
 #include "chromecast/public/volume_control.h"
 #include "media/audio/audio_device_description.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -80,4 +80,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MOCK_MIXER_SOURCE_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MOCK_MIXER_SOURCE_H_
diff --git a/chromecast/media/cma/backend/mock_post_processor_factory.cc b/chromecast/media/cma/backend/mixer/mock_post_processor_factory.cc
similarity index 97%
rename from chromecast/media/cma/backend/mock_post_processor_factory.cc
rename to chromecast/media/cma/backend/mixer/mock_post_processor_factory.cc
index ee6b78f..a62634d 100644
--- a/chromecast/media/cma/backend/mock_post_processor_factory.cc
+++ b/chromecast/media/cma/backend/mixer/mock_post_processor_factory.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/backend/mock_post_processor_factory.h"
+#include "chromecast/media/cma/backend/mixer/mock_post_processor_factory.h"
 
 #include "base/logging.h"
 #include "base/values.h"
diff --git a/chromecast/media/cma/backend/mock_post_processor_factory.h b/chromecast/media/cma/backend/mixer/mock_post_processor_factory.h
similarity index 89%
rename from chromecast/media/cma/backend/mock_post_processor_factory.h
rename to chromecast/media/cma/backend/mixer/mock_post_processor_factory.h
index 5b196bfb..571e674 100644
--- a/chromecast/media/cma/backend/mock_post_processor_factory.h
+++ b/chromecast/media/cma/backend/mixer/mock_post_processor_factory.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MOCK_POST_PROCESSOR_FACTORY_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MOCK_POST_PROCESSOR_FACTORY_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MOCK_POST_PROCESSOR_FACTORY_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MOCK_POST_PROCESSOR_FACTORY_H_
 
 #include <memory>
 #include <string>
 #include <unordered_map>
 
 #include "base/macros.h"
-#include "chromecast/media/cma/backend/post_processing_pipeline.h"
+#include "chromecast/media/cma/backend/mixer/post_processing_pipeline.h"
 #include "chromecast/public/media/audio_post_processor2_shlib.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -57,7 +57,6 @@
                          bool is_silence) {
     output_buffer_ = data;
     return static_cast<double>(rendering_delay_frames_) / sample_rate_;
-    ;
   }
 
   MockPostProcessorFactory* const factory_;
@@ -86,4 +85,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MOCK_POST_PROCESSOR_FACTORY_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MOCK_POST_PROCESSOR_FACTORY_H_
diff --git a/chromecast/media/cma/backend/mock_redirected_audio_output.cc b/chromecast/media/cma/backend/mixer/mock_redirected_audio_output.cc
similarity index 94%
rename from chromecast/media/cma/backend/mock_redirected_audio_output.cc
rename to chromecast/media/cma/backend/mixer/mock_redirected_audio_output.cc
index 571644a..45aac44 100644
--- a/chromecast/media/cma/backend/mock_redirected_audio_output.cc
+++ b/chromecast/media/cma/backend/mixer/mock_redirected_audio_output.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 "chromecast/media/cma/backend/mock_redirected_audio_output.h"
+#include "chromecast/media/cma/backend/mixer/mock_redirected_audio_output.h"
 
 #include <algorithm>
 
diff --git a/chromecast/media/cma/backend/mock_redirected_audio_output.h b/chromecast/media/cma/backend/mixer/mock_redirected_audio_output.h
similarity index 85%
rename from chromecast/media/cma/backend/mock_redirected_audio_output.h
rename to chromecast/media/cma/backend/mixer/mock_redirected_audio_output.h
index 7e8e64a..4fe3d87e 100644
--- a/chromecast/media/cma/backend/mock_redirected_audio_output.h
+++ b/chromecast/media/cma/backend/mixer/mock_redirected_audio_output.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 CHROMECAST_MEDIA_CMA_BACKEND_MOCK_REDIRECTED_AUDIO_OUTPUT_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MOCK_REDIRECTED_AUDIO_OUTPUT_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MOCK_REDIRECTED_AUDIO_OUTPUT_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MOCK_REDIRECTED_AUDIO_OUTPUT_H_
 
 #include <cstdint>
 #include <memory>
@@ -51,4 +51,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MOCK_REDIRECTED_AUDIO_OUTPUT_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MOCK_REDIRECTED_AUDIO_OUTPUT_H_
diff --git a/chromecast/media/cma/backend/post_processing_pipeline.h b/chromecast/media/cma/backend/mixer/post_processing_pipeline.h
similarity index 87%
rename from chromecast/media/cma/backend/post_processing_pipeline.h
rename to chromecast/media/cma/backend/mixer/post_processing_pipeline.h
index 986bf6a..6dd488b 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline.h
+++ b/chromecast/media/cma/backend/mixer/post_processing_pipeline.h
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSING_PIPELINE_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSING_PIPELINE_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSING_PIPELINE_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSING_PIPELINE_H_
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "chromecast/public/media/audio_post_processor2_shlib.h"
@@ -53,4 +54,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSING_PIPELINE_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSING_PIPELINE_H_
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_impl.cc b/chromecast/media/cma/backend/mixer/post_processing_pipeline_impl.cc
similarity index 98%
rename from chromecast/media/cma/backend/post_processing_pipeline_impl.cc
rename to chromecast/media/cma/backend/mixer/post_processing_pipeline_impl.cc
index 3aabc58..86036d54 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_impl.cc
+++ b/chromecast/media/cma/backend/mixer/post_processing_pipeline_impl.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 "chromecast/media/cma/backend/post_processing_pipeline_impl.h"
+#include "chromecast/media/cma/backend/mixer/post_processing_pipeline_impl.h"
 
 #include <algorithm>
 #include <cmath>
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_impl.h b/chromecast/media/cma/backend/mixer/post_processing_pipeline_impl.h
similarity index 88%
rename from chromecast/media/cma/backend/post_processing_pipeline_impl.h
rename to chromecast/media/cma/backend/mixer/post_processing_pipeline_impl.h
index f604acf9..b72d0b6 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_impl.h
+++ b/chromecast/media/cma/backend/mixer/post_processing_pipeline_impl.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 CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSING_PIPELINE_IMPL_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSING_PIPELINE_IMPL_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSING_PIPELINE_IMPL_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSING_PIPELINE_IMPL_H_
 
 #include <memory>
 #include <string>
@@ -11,8 +11,8 @@
 
 #include "base/macros.h"
 #include "chromecast/media/base/aligned_buffer.h"
-#include "chromecast/media/cma/backend/post_processing_pipeline.h"
-#include "chromecast/media/cma/backend/post_processor_factory.h"
+#include "chromecast/media/cma/backend/mixer/post_processing_pipeline.h"
+#include "chromecast/media/cma/backend/mixer/post_processor_factory.h"
 #include "chromecast/public/volume_control.h"
 
 namespace base {
@@ -99,4 +99,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSING_PIPELINE_IMPL_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSING_PIPELINE_IMPL_H_
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_parser.cc b/chromecast/media/cma/backend/mixer/post_processing_pipeline_parser.cc
similarity index 98%
rename from chromecast/media/cma/backend/post_processing_pipeline_parser.cc
rename to chromecast/media/cma/backend/mixer/post_processing_pipeline_parser.cc
index d969fbe..b2154d2 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_parser.cc
+++ b/chromecast/media/cma/backend/mixer/post_processing_pipeline_parser.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 "chromecast/media/cma/backend/post_processing_pipeline_parser.h"
+#include "chromecast/media/cma/backend/mixer/post_processing_pipeline_parser.h"
 
 #include <utility>
 
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_parser.h b/chromecast/media/cma/backend/mixer/post_processing_pipeline_parser.h
similarity index 90%
rename from chromecast/media/cma/backend/post_processing_pipeline_parser.h
rename to chromecast/media/cma/backend/mixer/post_processing_pipeline_parser.h
index ba4852e0..f8d5d56e 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_parser.h
+++ b/chromecast/media/cma/backend/mixer/post_processing_pipeline_parser.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 CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSING_PIPELINE_PARSER_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSING_PIPELINE_PARSER_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSING_PIPELINE_PARSER_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSING_PIPELINE_PARSER_H_
 
 #include <memory>
 #include <string>
@@ -77,4 +77,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSING_PIPELINE_PARSER_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSING_PIPELINE_PARSER_H_
diff --git a/chromecast/media/cma/backend/post_processor_factory.cc b/chromecast/media/cma/backend/mixer/post_processor_factory.cc
similarity index 80%
rename from chromecast/media/cma/backend/post_processor_factory.cc
rename to chromecast/media/cma/backend/mixer/post_processor_factory.cc
index c98fd4a3..1a0897d 100644
--- a/chromecast/media/cma/backend/post_processor_factory.cc
+++ b/chromecast/media/cma/backend/mixer/post_processor_factory.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/backend/post_processor_factory.h"
+#include "chromecast/media/cma/backend/mixer/post_processor_factory.h"
 
 #include <memory>
 
@@ -11,7 +11,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/scoped_native_library.h"
 #include "base/strings/stringprintf.h"
-#include "chromecast/media/cma/backend/post_processors/post_processor_wrapper.h"
+#include "chromecast/media/cma/backend/mixer/post_processor_paths.h"
+#include "chromecast/media/cma/backend/mixer/post_processors/post_processor_wrapper.h"
 #include "chromecast/public/media/audio_post_processor2_shlib.h"
 #include "chromecast/public/media/audio_post_processor_shlib.h"
 
@@ -22,23 +23,22 @@
 
 const char kV1SoCreateFunction[] = "AudioPostProcessorShlib_Create";
 const char kV2SoCreateFunction[] = "AudioPostProcessor2Shlib_Create";
-const char kPreferredLibraryPath[] = "/system/chrome/lib/processors";
-const char kPreferredOemLibraryPath[] = "/oem_cast_shlib/processors";
 
 base::FilePath FindLibrary(const std::string& library_name) {
   base::FilePath relative_path(library_name);
-  base::FilePath full_path(kPreferredLibraryPath);
+  base::FilePath full_path = GetPostProcessorDirectory();
   full_path = full_path.Append(relative_path);
   if (base::PathExists(full_path)) {
     return full_path;
   }
-  full_path = base::FilePath(kPreferredOemLibraryPath);
+  full_path = GetOemPostProcessorDirectory();
   full_path = full_path.Append(relative_path);
   if (base::PathExists(full_path)) {
     return full_path;
   }
-  LOG(WARNING) << library_name << " not found in " << kPreferredLibraryPath
-               << " or " << kPreferredOemLibraryPath
+  LOG(WARNING) << library_name << " not found in "
+               << GetPostProcessorDirectory().AsUTF8Unsafe() << " or "
+               << GetOemPostProcessorDirectory().AsUTF8Unsafe()
                << ". Prefer storing post processors in these directories.";
   return relative_path;
 }
@@ -104,15 +104,5 @@
   return false;
 }
 
-// static
-base::FilePath const PostProcessorFactory::GetPostProcessorDirectory() {
-  return base::FilePath(kPreferredLibraryPath);
-}
-
-// static
-base::FilePath const PostProcessorFactory::GetOemPostProcessorDirectory() {
-  return base::FilePath(kPreferredOemLibraryPath);
-}
-
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cma/backend/post_processor_factory.h b/chromecast/media/cma/backend/mixer/post_processor_factory.h
similarity index 76%
rename from chromecast/media/cma/backend/post_processor_factory.h
rename to chromecast/media/cma/backend/mixer/post_processor_factory.h
index afc5584..54b3ffb 100644
--- a/chromecast/media/cma/backend/post_processor_factory.h
+++ b/chromecast/media/cma/backend/mixer/post_processor_factory.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 CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSOR_FACTORY_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSOR_FACTORY_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSOR_FACTORY_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSOR_FACTORY_H_
 
 #include <memory>
 #include <string>
@@ -29,12 +29,6 @@
   // Checks if a library is a V1 or V2 post processor.
   static bool IsPostProcessorLibrary(const base::FilePath& library_path);
 
-  // Returns the preferred directory for 1P Post Processors.
-  static base::FilePath const GetPostProcessorDirectory();
-
-  // Returns the preferred directroy for 3P Post Processors.
-  static base::FilePath const GetOemPostProcessorDirectory();
-
   // Creates an instance of AudioPostProcessor2 or a wrapped AudioPostProcessor.
   // By default, will attempt to find the library in
   // /system/chrome/lib/processors/|library_name|. Will fall back to
@@ -56,4 +50,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSOR_FACTORY_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSOR_FACTORY_H_
diff --git a/chromecast/media/cma/backend/mixer/post_processor_paths.cc b/chromecast/media/cma/backend/mixer/post_processor_paths.cc
new file mode 100644
index 0000000..4276919
--- /dev/null
+++ b/chromecast/media/cma/backend/mixer/post_processor_paths.cc
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/media/cma/backend/mixer/post_processor_paths.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+
+const char kPreferredLibraryPath[] = "/system/chrome/lib/processors";
+const char kPreferredOemLibraryPath[] = "/oem_cast_shlib/processors";
+
+}  // namespace
+
+// static
+base::FilePath GetPostProcessorDirectory() {
+  return base::FilePath(kPreferredLibraryPath);
+}
+
+// static
+base::FilePath GetOemPostProcessorDirectory() {
+  return base::FilePath(kPreferredOemLibraryPath);
+}
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/media/cma/backend/mixer/post_processor_paths.h b/chromecast/media/cma/backend/mixer/post_processor_paths.h
new file mode 100644
index 0000000..5e7cc5e
--- /dev/null
+++ b/chromecast/media/cma/backend/mixer/post_processor_paths.h
@@ -0,0 +1,22 @@
+// 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 CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSOR_PATHS_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSOR_PATHS_H_
+
+#include "base/files/file_path.h"
+
+namespace chromecast {
+namespace media {
+
+// Returns the preferred directory for 1P Post Processors.
+base::FilePath GetPostProcessorDirectory();
+
+// Returns the preferred directory for 3P Post Processors.
+base::FilePath GetOemPostProcessorDirectory();
+
+}  // namespace media
+}  // namespace chromecast
+
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSOR_PATHS_H_
diff --git a/chromecast/media/cma/backend/post_processors/BUILD.gn b/chromecast/media/cma/backend/mixer/post_processors/BUILD.gn
similarity index 91%
rename from chromecast/media/cma/backend/post_processors/BUILD.gn
rename to chromecast/media/cma/backend/mixer/post_processors/BUILD.gn
index ec7def2..6adcbe3c 100644
--- a/chromecast/media/cma/backend/post_processors/BUILD.gn
+++ b/chromecast/media/cma/backend/mixer/post_processors/BUILD.gn
@@ -22,7 +22,7 @@
   ]
   defines = [
     "DEFINED_POSTPROCESSOR_NAME=chromecast::media::Governor",
-    "DEFINED_POSTPROCESSOR_HEADER=chromecast/media/cma/backend/post_processors/governor.h",
+    "DEFINED_POSTPROCESSOR_HEADER=chromecast/media/cma/backend/mixer/post_processors/governor.h",
   ]
   deps = [
     ":governor",
@@ -54,7 +54,7 @@
   ]
   defines = [
     "DEFINED_POSTPROCESSOR_NAME=chromecast::media::SaturatedGain",
-    "DEFINED_POSTPROCESSOR_HEADER=chromecast/media/cma/backend/post_processors/saturated_gain.h",
+    "DEFINED_POSTPROCESSOR_HEADER=chromecast/media/cma/backend/mixer/post_processors/saturated_gain.h",
   ]
   deps = [
     ":saturated_gain",
diff --git a/chromecast/media/cma/backend/post_processors/governor.cc b/chromecast/media/cma/backend/mixer/post_processors/governor.cc
similarity index 97%
rename from chromecast/media/cma/backend/post_processors/governor.cc
rename to chromecast/media/cma/backend/mixer/post_processors/governor.cc
index 363abdb..656651b 100644
--- a/chromecast/media/cma/backend/post_processors/governor.cc
+++ b/chromecast/media/cma/backend/mixer/post_processors/governor.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 "chromecast/media/cma/backend/post_processors/governor.h"
+#include "chromecast/media/cma/backend/mixer/post_processors/governor.h"
 
 #include <limits>
 #include <memory>
diff --git a/chromecast/media/cma/backend/post_processors/governor.h b/chromecast/media/cma/backend/mixer/post_processors/governor.h
similarity index 87%
rename from chromecast/media/cma/backend/post_processors/governor.h
rename to chromecast/media/cma/backend/mixer/post_processors/governor.h
index 3c39973..dd1c813 100644
--- a/chromecast/media/cma/backend/post_processors/governor.h
+++ b/chromecast/media/cma/backend/mixer/post_processors/governor.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 CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_GOVERNOR_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_GOVERNOR_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_GOVERNOR_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_GOVERNOR_H_
 
 #include <memory>
 #include <string>
@@ -54,4 +54,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_GOVERNOR_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_GOVERNOR_H_
diff --git a/chromecast/media/cma/backend/post_processors/governor_unittest.cc b/chromecast/media/cma/backend/mixer/post_processors/governor_unittest.cc
similarity index 96%
rename from chromecast/media/cma/backend/post_processors/governor_unittest.cc
rename to chromecast/media/cma/backend/mixer/post_processors/governor_unittest.cc
index f455ce8..60e87c3 100644
--- a/chromecast/media/cma/backend/post_processors/governor_unittest.cc
+++ b/chromecast/media/cma/backend/mixer/post_processors/governor_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/backend/post_processors/governor.h"
+#include "chromecast/media/cma/backend/mixer/post_processors/governor.h"
 
 #include <cmath>
 #include <cstdint>
@@ -14,7 +14,7 @@
 #include "base/macros.h"
 #include "base/strings/stringprintf.h"
 #include "chromecast/media/base/aligned_buffer.h"
-#include "chromecast/media/cma/backend/post_processors/post_processor_unittest.h"
+#include "chromecast/media/cma/backend/mixer/post_processors/post_processor_unittest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromecast {
diff --git a/chromecast/media/cma/backend/post_processors/post_processor_name.cc b/chromecast/media/cma/backend/mixer/post_processors/post_processor_name.cc
similarity index 92%
rename from chromecast/media/cma/backend/post_processors/post_processor_name.cc
rename to chromecast/media/cma/backend/mixer/post_processors/post_processor_name.cc
index d630542f..0f480ec 100644
--- a/chromecast/media/cma/backend/post_processors/post_processor_name.cc
+++ b/chromecast/media/cma/backend/mixer/post_processors/post_processor_name.cc
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chromecast/public/chromecast_export.h"
 #include "chromecast/public/media/audio_post_processor2_shlib.h"
-#include "chromecast_export.h"
 
 #define STRINGIFY(x) #x
 #define STRINGIFY_WRAPPER(x) STRINGIFY(x)
diff --git a/chromecast/media/cma/backend/post_processors/post_processor_unittest.cc b/chromecast/media/cma/backend/mixer/post_processors/post_processor_unittest.cc
similarity index 98%
rename from chromecast/media/cma/backend/post_processors/post_processor_unittest.cc
rename to chromecast/media/cma/backend/mixer/post_processors/post_processor_unittest.cc
index 77efe58..8c346f9 100644
--- a/chromecast/media/cma/backend/post_processors/post_processor_unittest.cc
+++ b/chromecast/media/cma/backend/mixer/post_processors/post_processor_unittest.cc
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/backend/post_processors/post_processor_unittest.h"
-#include "chromecast/media/cma/backend/post_processors/post_processor_wrapper.h"
+#include "chromecast/media/cma/backend/mixer/post_processors/post_processor_unittest.h"
+#include "chromecast/media/cma/backend/mixer/post_processors/post_processor_wrapper.h"
 
 #include <time.h>
 
diff --git a/chromecast/media/cma/backend/post_processors/post_processor_unittest.h b/chromecast/media/cma/backend/mixer/post_processors/post_processor_unittest.h
similarity index 94%
rename from chromecast/media/cma/backend/post_processors/post_processor_unittest.h
rename to chromecast/media/cma/backend/mixer/post_processors/post_processor_unittest.h
index 6d9a84d3..85ed7b6 100644
--- a/chromecast/media/cma/backend/post_processors/post_processor_unittest.h
+++ b/chromecast/media/cma/backend/mixer/post_processors/post_processor_unittest.h
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_POST_PROCESSOR_UNITTEST_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_POST_PROCESSOR_UNITTEST_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_POST_PROCESSOR_UNITTEST_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_POST_PROCESSOR_UNITTEST_H_
 
+#include <string>
 #include <vector>
 
 #include "chromecast/media/base/aligned_buffer.h"
@@ -129,4 +130,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_POST_PROCESSOR_UNITTEST_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_POST_PROCESSOR_UNITTEST_H_
diff --git a/chromecast/media/cma/backend/post_processors/post_processor_wrapper.cc b/chromecast/media/cma/backend/mixer/post_processors/post_processor_wrapper.cc
similarity index 95%
rename from chromecast/media/cma/backend/post_processors/post_processor_wrapper.cc
rename to chromecast/media/cma/backend/mixer/post_processors/post_processor_wrapper.cc
index b51d5a3..1f94b56 100644
--- a/chromecast/media/cma/backend/post_processors/post_processor_wrapper.cc
+++ b/chromecast/media/cma/backend/mixer/post_processors/post_processor_wrapper.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 "chromecast/media/cma/backend/post_processors/post_processor_wrapper.h"
+#include "chromecast/media/cma/backend/mixer/post_processors/post_processor_wrapper.h"
 
 #include "base/logging.h"
 #include "chromecast/public/media/audio_post_processor_shlib.h"
diff --git a/chromecast/media/cma/backend/post_processors/post_processor_wrapper.h b/chromecast/media/cma/backend/mixer/post_processors/post_processor_wrapper.h
similarity index 87%
rename from chromecast/media/cma/backend/post_processors/post_processor_wrapper.h
rename to chromecast/media/cma/backend/mixer/post_processors/post_processor_wrapper.h
index b90c65c..3914fd6 100644
--- a/chromecast/media/cma/backend/post_processors/post_processor_wrapper.h
+++ b/chromecast/media/cma/backend/mixer/post_processors/post_processor_wrapper.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 CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_POST_PROCESSOR_WRAPPER_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_POST_PROCESSOR_WRAPPER_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_POST_PROCESSOR_WRAPPER_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_POST_PROCESSOR_WRAPPER_H_
 
 // Provides a wrapper for AudioPostProcessor to allow using it as an
 // AudioPostProcessor2. This works by simply fowarding the input buffer as the
@@ -58,4 +58,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_POST_PROCESSOR_WRAPPER_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_POST_PROCESSOR_WRAPPER_H_
diff --git a/chromecast/media/cma/backend/post_processors/saturated_gain.cc b/chromecast/media/cma/backend/mixer/post_processors/saturated_gain.cc
similarity index 96%
rename from chromecast/media/cma/backend/post_processors/saturated_gain.cc
rename to chromecast/media/cma/backend/mixer/post_processors/saturated_gain.cc
index 09112ae..c8da345 100644
--- a/chromecast/media/cma/backend/post_processors/saturated_gain.cc
+++ b/chromecast/media/cma/backend/mixer/post_processors/saturated_gain.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 "chromecast/media/cma/backend/post_processors/saturated_gain.h"
+#include "chromecast/media/cma/backend/mixer/post_processors/saturated_gain.h"
 
 #include <algorithm>
 #include <cmath>
diff --git a/chromecast/media/cma/backend/post_processors/saturated_gain.h b/chromecast/media/cma/backend/mixer/post_processors/saturated_gain.h
similarity index 82%
rename from chromecast/media/cma/backend/post_processors/saturated_gain.h
rename to chromecast/media/cma/backend/mixer/post_processors/saturated_gain.h
index 3c656ff..4e9dd20 100644
--- a/chromecast/media/cma/backend/post_processors/saturated_gain.h
+++ b/chromecast/media/cma/backend/mixer/post_processors/saturated_gain.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 CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_SATURATED_GAIN_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_SATURATED_GAIN_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_SATURATED_GAIN_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_SATURATED_GAIN_H_
 
 #include <string>
 
@@ -41,4 +41,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_POST_PROCESSORS_SATURATED_GAIN_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_POST_PROCESSORS_SATURATED_GAIN_H_
diff --git a/chromecast/media/cma/backend/post_processors/saturated_gain_unittest.cc b/chromecast/media/cma/backend/mixer/post_processors/saturated_gain_unittest.cc
similarity index 91%
rename from chromecast/media/cma/backend/post_processors/saturated_gain_unittest.cc
rename to chromecast/media/cma/backend/mixer/post_processors/saturated_gain_unittest.cc
index 4864d56c..7f41c3a 100644
--- a/chromecast/media/cma/backend/post_processors/saturated_gain_unittest.cc
+++ b/chromecast/media/cma/backend/mixer/post_processors/saturated_gain_unittest.cc
@@ -6,8 +6,8 @@
 #include <vector>
 
 #include "base/strings/stringprintf.h"
-#include "chromecast/media/cma/backend/post_processors/post_processor_unittest.h"
-#include "chromecast/media/cma/backend/post_processors/saturated_gain.h"
+#include "chromecast/media/cma/backend/mixer/post_processors/post_processor_unittest.h"
+#include "chromecast/media/cma/backend/mixer/post_processors/saturated_gain.h"
 
 namespace chromecast {
 namespace media {
@@ -15,8 +15,7 @@
 
 namespace {
 
-const char kConfigTemplate[] =
-    R"config({"gain_db": %f})config";
+const char kConfigTemplate[] = R"config({"gain_db": %f})config";
 
 std::string MakeConfigString(float gain_db) {
   return base::StringPrintf(kConfigTemplate, gain_db);
diff --git a/chromecast/media/cma/backend/stream_mixer.cc b/chromecast/media/cma/backend/mixer/stream_mixer.cc
similarity index 98%
rename from chromecast/media/cma/backend/stream_mixer.cc
rename to chromecast/media/cma/backend/mixer/stream_mixer.cc
index fee7f54..da5456b5 100644
--- a/chromecast/media/cma/backend/stream_mixer.cc
+++ b/chromecast/media/cma/backend/mixer/stream_mixer.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 "chromecast/media/cma/backend/stream_mixer.h"
+#include "chromecast/media/cma/backend/mixer/stream_mixer.h"
 
 #include <pthread.h>
 
@@ -26,13 +26,13 @@
 #include "chromecast/base/serializers.h"
 #include "chromecast/base/thread_health_checker.h"
 #include "chromecast/media/base/audio_device_ids.h"
-#include "chromecast/media/cma/backend/audio_output_redirector.h"
 #include "chromecast/media/cma/backend/cast_audio_json.h"
-#include "chromecast/media/cma/backend/filter_group.h"
 #include "chromecast/media/cma/backend/interleaved_channel_mixer.h"
-#include "chromecast/media/cma/backend/mixer_service_receiver.h"
-#include "chromecast/media/cma/backend/post_processing_pipeline_impl.h"
-#include "chromecast/media/cma/backend/post_processing_pipeline_parser.h"
+#include "chromecast/media/cma/backend/mixer/audio_output_redirector.h"
+#include "chromecast/media/cma/backend/mixer/filter_group.h"
+#include "chromecast/media/cma/backend/mixer/mixer_service_receiver.h"
+#include "chromecast/media/cma/backend/mixer/post_processing_pipeline_impl.h"
+#include "chromecast/media/cma/backend/mixer/post_processing_pipeline_parser.h"
 #include "chromecast/public/media/mixer_output_stream.h"
 #include "media/audio/audio_device_description.h"
 
diff --git a/chromecast/media/cma/backend/stream_mixer.h b/chromecast/media/cma/backend/mixer/stream_mixer.h
similarity index 95%
rename from chromecast/media/cma/backend/stream_mixer.h
rename to chromecast/media/cma/backend/mixer/stream_mixer.h
index 9108993f..d9f7d522 100644
--- a/chromecast/media/cma/backend/stream_mixer.h
+++ b/chromecast/media/cma/backend/mixer/stream_mixer.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 CHROMECAST_MEDIA_CMA_BACKEND_STREAM_MIXER_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_STREAM_MIXER_H_
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_STREAM_MIXER_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_STREAM_MIXER_H_
 
 #include <stdint.h>
 
@@ -22,10 +22,10 @@
 #include "base/threading/sequence_bound.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
-#include "chromecast/media/cma/backend/loopback_handler.h"
-#include "chromecast/media/cma/backend/mixer_control.h"
-#include "chromecast/media/cma/backend/mixer_input.h"
-#include "chromecast/media/cma/backend/mixer_pipeline.h"
+#include "chromecast/media/cma/backend/mixer/loopback_handler.h"
+#include "chromecast/media/cma/backend/mixer/mixer_control.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input.h"
+#include "chromecast/media/cma/backend/mixer/mixer_pipeline.h"
 #include "chromecast/public/cast_media_shlib.h"
 #include "chromecast/public/media/external_audio_pipeline_shlib.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
@@ -249,4 +249,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_STREAM_MIXER_H_
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_STREAM_MIXER_H_
diff --git a/chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc b/chromecast/media/cma/backend/mixer/stream_mixer_external_audio_pipeline_unittest.cc
similarity index 97%
rename from chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc
rename to chromecast/media/cma/backend/mixer/stream_mixer_external_audio_pipeline_unittest.cc
index c46f573..85c8099 100644
--- a/chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc
+++ b/chromecast/media/cma/backend/mixer/stream_mixer_external_audio_pipeline_unittest.cc
@@ -13,9 +13,9 @@
 #include "base/run_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromecast/media/audio/fake_external_audio_pipeline_support.h"
-#include "chromecast/media/cma/backend/mock_mixer_source.h"
-#include "chromecast/media/cma/backend/mock_post_processor_factory.h"
-#include "chromecast/media/cma/backend/stream_mixer.h"
+#include "chromecast/media/cma/backend/mixer/mock_mixer_source.h"
+#include "chromecast/media/cma/backend/mixer/mock_post_processor_factory.h"
+#include "chromecast/media/cma/backend/mixer/stream_mixer.h"
 #include "chromecast/public/media/external_audio_pipeline_shlib.h"
 #include "chromecast/public/media/mixer_output_stream.h"
 #include "media/base/audio_bus.h"
diff --git a/chromecast/media/cma/backend/stream_mixer_unittest.cc b/chromecast/media/cma/backend/mixer/stream_mixer_unittest.cc
similarity index 97%
rename from chromecast/media/cma/backend/stream_mixer_unittest.cc
rename to chromecast/media/cma/backend/mixer/stream_mixer_unittest.cc
index c36d574..21d81473 100644
--- a/chromecast/media/cma/backend/stream_mixer_unittest.cc
+++ b/chromecast/media/cma/backend/mixer/stream_mixer_unittest.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/media/cma/backend/stream_mixer.h"
-
 #include <algorithm>
 #include <cmath>
 #include <limits>
@@ -18,11 +16,12 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
-#include "chromecast/media/cma/backend/audio_output_redirector.h"
-#include "chromecast/media/cma/backend/mixer_input.h"
-#include "chromecast/media/cma/backend/mock_mixer_source.h"
-#include "chromecast/media/cma/backend/mock_post_processor_factory.h"
-#include "chromecast/media/cma/backend/mock_redirected_audio_output.h"
+#include "chromecast/media/cma/backend/mixer/audio_output_redirector.h"
+#include "chromecast/media/cma/backend/mixer/mixer_input.h"
+#include "chromecast/media/cma/backend/mixer/mock_mixer_source.h"
+#include "chromecast/media/cma/backend/mixer/mock_post_processor_factory.h"
+#include "chromecast/media/cma/backend/mixer/mock_redirected_audio_output.h"
+#include "chromecast/media/cma/backend/mixer/stream_mixer.h"
 #include "chromecast/public/media/mixer_output_stream.h"
 #include "chromecast/public/volume_control.h"
 #include "media/audio/audio_device_description.h"
@@ -847,13 +846,26 @@
 
   const int32_t kMaxSample = std::numeric_limits<int32_t>::max();
   const int32_t kMinSample = std::numeric_limits<int32_t>::min();
-  const int32_t kEdgeData[2][8] = {
-      {
-          kMinSample, kMinSample, kMinSample, 0.0, 0.0, kMaxSample, 0.0, 0.0,
-      },
-      {
-          kMinSample, 0.0, kMaxSample, 0.0, kMaxSample, kMaxSample, 0.0, 0.0,
-      }};
+  const int32_t kEdgeData[2][8] = {{
+                                       kMinSample,
+                                       kMinSample,
+                                       kMinSample,
+                                       0.0,
+                                       0.0,
+                                       kMaxSample,
+                                       0.0,
+                                       0.0,
+                                   },
+                                   {
+                                       kMinSample,
+                                       0.0,
+                                       kMaxSample,
+                                       0.0,
+                                       kMaxSample,
+                                       kMaxSample,
+                                       0.0,
+                                       0.0,
+                                   }};
 
   // Hand-calculate the results. Index 0 is clamped to -(2^31). Index 5 is
   // clamped to 2^31-1.
@@ -1084,7 +1096,7 @@
       kDelayModuleSolib, "delayer_2",  // non-unique processor names
       kDelayModuleSolib, "delayer_2",
       kDelayModuleSolib  // intentionally omitted processor name
-      );
+  );
 
   auto factory = std::make_unique<MockPostProcessorFactory>();
   MockPostProcessorFactory* factory_ptr = factory.get();
diff --git a/chromecast/media/cma/backend/video/BUILD.gn b/chromecast/media/cma/backend/video/BUILD.gn
index 8795474..1a3a6e1 100644
--- a/chromecast/media/cma/backend/video/BUILD.gn
+++ b/chromecast/media/cma/backend/video/BUILD.gn
@@ -54,7 +54,7 @@
   ]
 
   if (use_alsa) {
-    deps += [ "//chromecast/media/cma/backend/alsa:cma_backend_support" ]
+    deps += [ "//chromecast/media/cma/backend/alsa:volume_control" ]
     if (!is_cast_desktop_build) {
       libs = [ "videodecoderformixer" ]
     } else {
diff --git a/chromecast/media/cma/backend/volume_control.cc b/chromecast/media/cma/backend/volume_control.cc
index 744365a..d3189846 100644
--- a/chromecast/media/cma/backend/volume_control.cc
+++ b/chromecast/media/cma/backend/volume_control.cc
@@ -27,12 +27,10 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #include "base/values.h"
-#include "chromecast/base/init_command_line_shlib.h"
 #include "chromecast/base/serializers.h"
 #include "chromecast/media/cma/backend/audio_buildflags.h"
 #include "chromecast/media/cma/backend/cast_audio_json.h"
-#include "chromecast/media/cma/backend/post_processing_pipeline_parser.h"
-#include "chromecast/media/cma/backend/stream_mixer.h"
+#include "chromecast/media/cma/backend/mixer/stream_mixer.h"
 #include "chromecast/media/cma/backend/system_volume_control.h"
 #include "chromecast/media/cma/backend/volume_map.h"
 
@@ -70,11 +68,6 @@
   }
 }
 
-VolumeMap& GetVolumeMap() {
-  static base::NoDestructor<VolumeMap> volume_map;
-  return *volume_map;
-}
-
 class VolumeControlInternal : public SystemVolumeControl::Delegate {
  public:
   VolumeControlInternal()
@@ -83,7 +76,7 @@
             base::WaitableEvent::ResetPolicy::MANUAL,
             base::WaitableEvent::InitialState::NOT_SIGNALED) {
     // Load volume map to check that the config file is correct.
-    GetVolumeMap();
+    VolumeControl::VolumeToDbFS(0.0f);
 
     stored_values_.SetDouble(kKeyMediaDbFS, kDefaultMediaDbFS);
     stored_values_.SetDouble(kKeyAlarmDbFS, kDefaultAlarmDbFS);
@@ -409,7 +402,6 @@
 
 // static
 void VolumeControl::Initialize(const std::vector<std::string>& argv) {
-  chromecast::InitCommandLineShlib(argv);
   GetVolumeControl();
 }
 
@@ -464,16 +456,6 @@
 }
 
 // static
-float VolumeControl::VolumeToDbFS(float volume) {
-  return GetVolumeMap().VolumeToDbFS(volume);
-}
-
-// static
-float VolumeControl::DbFSToVolume(float db) {
-  return GetVolumeMap().DbFSToVolume(db);
-}
-
-// static
 void VolumeControl::SetPowerSaveMode(bool power_save_on) {
   GetVolumeControl().SetPowerSaveMode(power_save_on);
 }
diff --git a/chromecast/media/cma/backend/volume_map.cc b/chromecast/media/cma/backend/volume_map.cc
index 9991ecb..f260676a 100644
--- a/chromecast/media/cma/backend/volume_map.cc
+++ b/chromecast/media/cma/backend/volume_map.cc
@@ -8,18 +8,26 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "base/no_destructor.h"
 #include "base/values.h"
 #include "chromecast/media/cma/backend/cast_audio_json.h"
+#include "chromecast/public/volume_control.h"
 
 namespace chromecast {
 namespace media {
 
 namespace {
+
 constexpr char kKeyVolumeMap[] = "volume_map";
 constexpr char kKeyLevel[] = "level";
 constexpr char kKeyDb[] = "db";
 constexpr float kMinDbFS = -120.0f;
 
+VolumeMap& GetVolumeMap() {
+  static base::NoDestructor<VolumeMap> volume_map;
+  return *volume_map;
+}
+
 }  // namespace
 
 VolumeMap::VolumeMap()
@@ -133,5 +141,15 @@
   volume_map_ = std::move(new_map);
 }
 
+// static
+float VolumeControl::VolumeToDbFS(float volume) {
+  return GetVolumeMap().VolumeToDbFS(volume);
+}
+
+// static
+float VolumeControl::DbFSToVolume(float db) {
+  return GetVolumeMap().DbFSToVolume(db);
+}
+
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/net/BUILD.gn b/chromecast/net/BUILD.gn
index 926bf45..c95ed56 100644
--- a/chromecast/net/BUILD.gn
+++ b/chromecast/net/BUILD.gn
@@ -34,6 +34,8 @@
     "//chromecast/public",
     "//components/proxy_config",
     "//net",
+    "//services/network/public/cpp",
+    "//services/network/public/mojom",
   ]
 
   if (is_fuchsia) {
diff --git a/chromecast/net/DEPS b/chromecast/net/DEPS
index 90e91a5..4ab9563 100644
--- a/chromecast/net/DEPS
+++ b/chromecast/net/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
   "+components/proxy_config",
   "+net",
+  "+services/network/public/cpp",
+  "+services/network/public/mojom",
 ]
diff --git a/chromecast/net/connectivity_checker.cc b/chromecast/net/connectivity_checker.cc
index 7c7a50aa..b82855a 100644
--- a/chromecast/net/connectivity_checker.cc
+++ b/chromecast/net/connectivity_checker.cc
@@ -6,13 +6,16 @@
 
 #include "base/single_thread_task_runner.h"
 #include "chromecast/net/connectivity_checker_impl.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace chromecast {
 
-ConnectivityChecker::ConnectivityChecker()
-    : connectivity_observer_list_(
-          new base::ObserverListThreadSafe<ConnectivityObserver>()) {
-}
+ConnectivityChecker::ConnectivityChecker(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    : RefCountedDeleteOnSequence(std::move(task_runner)),
+      connectivity_observer_list_(
+          base::MakeRefCounted<
+              base::ObserverListThreadSafe<ConnectivityObserver>>()) {}
 
 ConnectivityChecker::~ConnectivityChecker() {
 }
@@ -36,9 +39,12 @@
 // static
 scoped_refptr<ConnectivityChecker> ConnectivityChecker::Create(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-    net::URLRequestContextGetter* url_request_context_getter) {
+    std::unique_ptr<network::SharedURLLoaderFactoryInfo>
+        url_loader_factory_info,
+    network::NetworkConnectionTracker* network_connection_tracker) {
   return ConnectivityCheckerImpl::Create(task_runner,
-                                         url_request_context_getter);
+                                         std::move(url_loader_factory_info),
+                                         network_connection_tracker);
 }
 
 }  // namespace chromecast
diff --git a/chromecast/net/connectivity_checker.h b/chromecast/net/connectivity_checker.h
index 8c47710..85ad605 100644
--- a/chromecast/net/connectivity_checker.h
+++ b/chromecast/net/connectivity_checker.h
@@ -8,22 +8,24 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/ref_counted_delete_on_sequence.h"
 #include "base/observer_list_threadsafe.h"
+#include "base/sequenced_task_runner_helpers.h"
 
 namespace base {
 class SingleThreadTaskRunner;
 }
 
-namespace net {
-class URLRequestContextGetter;
-}
+namespace network {
+class SharedURLLoaderFactoryInfo;
+class NetworkConnectionTracker;
+}  // namespace network
 
 namespace chromecast {
 
 // Checks if internet connectivity is available.
 class ConnectivityChecker
-    : public base::RefCountedThreadSafe<ConnectivityChecker> {
+    : public base::RefCountedDeleteOnSequence<ConnectivityChecker> {
  public:
   class ConnectivityObserver {
    public:
@@ -40,9 +42,9 @@
 
   static scoped_refptr<ConnectivityChecker> Create(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-      net::URLRequestContextGetter* url_request_context_getter);
-
-  ConnectivityChecker();
+      std::unique_ptr<network::SharedURLLoaderFactoryInfo>
+          url_loader_factory_info,
+      network::NetworkConnectionTracker* network_connection_tracker);
 
   void AddConnectivityObserver(ConnectivityObserver* observer);
   void RemoveConnectivityObserver(ConnectivityObserver* observer);
@@ -54,13 +56,16 @@
   virtual void Check() = 0;
 
  protected:
+  explicit ConnectivityChecker(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
   virtual ~ConnectivityChecker();
 
   // Notifies observes that connectivity has changed.
   void Notify(bool connected);
 
  private:
-  friend class base::RefCountedThreadSafe<ConnectivityChecker>;
+  friend class base::RefCountedDeleteOnSequence<ConnectivityChecker>;
+  friend class base::DeleteHelper<ConnectivityChecker>;
 
   const scoped_refptr<base::ObserverListThreadSafe<ConnectivityObserver>>
       connectivity_observer_list_;
diff --git a/chromecast/net/connectivity_checker_impl.cc b/chromecast/net/connectivity_checker_impl.cc
index 7869fae..1e25d09 100644
--- a/chromecast/net/connectivity_checker_impl.cc
+++ b/chromecast/net/connectivity_checker_impl.cc
@@ -22,9 +22,10 @@
 #include "net/http/http_status_code.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/socket/ssl_client_socket.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_builder.h"
-#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/network_change_manager.mojom.h"
 
 namespace chromecast {
 
@@ -64,50 +65,59 @@
 // static
 scoped_refptr<ConnectivityCheckerImpl> ConnectivityCheckerImpl::Create(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    net::URLRequestContextGetter* url_request_context_getter) {
+    std::unique_ptr<network::SharedURLLoaderFactoryInfo>
+        url_loader_factory_info,
+    network::NetworkConnectionTracker* network_connection_tracker) {
   DCHECK(task_runner);
 
-  auto connectivity_checker =
-      base::WrapRefCounted(new ConnectivityCheckerImpl(task_runner));
+  auto connectivity_checker = base::WrapRefCounted(
+      new ConnectivityCheckerImpl(task_runner, network_connection_tracker));
   task_runner->PostTask(
       FROM_HERE,
       base::BindOnce(&ConnectivityCheckerImpl::Initialize, connectivity_checker,
-                     base::RetainedRef(url_request_context_getter)));
+                     std::move(url_loader_factory_info)));
   return connectivity_checker;
 }
 
 ConnectivityCheckerImpl::ConnectivityCheckerImpl(
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-    : ConnectivityChecker(),
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    network::NetworkConnectionTracker* network_connection_tracker)
+    : ConnectivityChecker(task_runner),
       task_runner_(std::move(task_runner)),
+      network_connection_tracker_(network_connection_tracker),
       connected_(false),
-      connection_type_(net::NetworkChangeNotifier::CONNECTION_NONE),
+      connection_type_(network::mojom::ConnectionType::CONNECTION_NONE),
       check_errors_(0),
-      network_changed_pending_(false) {
-  DCHECK(task_runner_.get());
+      network_changed_pending_(false),
+      weak_factory_(this) {
+  DCHECK(task_runner_);
+  DCHECK(network_connection_tracker_);
+  weak_this_ = weak_factory_.GetWeakPtr();
 }
 
 void ConnectivityCheckerImpl::Initialize(
-    net::URLRequestContextGetter* url_request_context_getter) {
-  url_request_context_getter_ = url_request_context_getter;
+    std::unique_ptr<network::SharedURLLoaderFactoryInfo>
+        url_loader_factory_info) {
   DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(url_loader_factory_info);
+  url_loader_factory_ = network::SharedURLLoaderFactory::Create(
+      std::move(url_loader_factory_info));
+
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   base::CommandLine::StringType check_url_str =
       command_line->GetSwitchValueNative(switches::kConnectivityCheckUrl);
   connectivity_check_url_.reset(new GURL(
       check_url_str.empty() ? kDefaultConnectivityCheckUrl : check_url_str));
 
-  url_request_context_ = url_request_context_getter->GetURLRequestContext();
+  network_connection_tracker_->AddNetworkConnectionObserver(this);
 
-  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
-  task_runner_->PostTask(FROM_HERE,
-                         base::BindOnce(&ConnectivityCheckerImpl::Check, this));
+  Check();
 }
 
 ConnectivityCheckerImpl::~ConnectivityCheckerImpl() {
-  DCHECK(task_runner_.get());
-  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
-  task_runner_->DeleteSoon(FROM_HERE, url_request_.release());
+  DCHECK(task_runner_);
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  network_connection_tracker_->RemoveNetworkConnectionObserver(this);
 }
 
 bool ConnectivityCheckerImpl::Connected() const {
@@ -117,18 +127,18 @@
 
 void ConnectivityCheckerImpl::SetConnected(bool connected) {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  if (connected_ == connected)
-    return;
   {
     base::AutoLock auto_lock(connected_lock_);
+    if (connected_ == connected) {
+      return;
+    }
     connected_ = connected;
   }
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   base::CommandLine::StringType check_url_str =
       command_line->GetSwitchValueNative(switches::kConnectivityCheckUrl);
-  if (check_url_str.empty())
-  {
+  if (check_url_str.empty()) {
     connectivity_check_url_.reset(new GURL(
       connected ? kHttpConnectivityCheckUrl : kDefaultConnectivityCheckUrl));
     LOG(INFO) << "Change check url=" << *connectivity_check_url_;
@@ -140,32 +150,48 @@
 
 void ConnectivityCheckerImpl::Check() {
   task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&ConnectivityCheckerImpl::CheckInternal, this));
+      FROM_HERE,
+      base::BindOnce(&ConnectivityCheckerImpl::CheckInternal, weak_this_));
 }
 
 void ConnectivityCheckerImpl::CheckInternal() {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  DCHECK(url_request_context_);
+  DCHECK(url_loader_factory_);
 
   // Don't check connectivity if network is offline, because Internet could be
   // accessible via netifs ignored.
-  if (net::NetworkChangeNotifier::IsOffline())
+  auto connection_type = network::mojom::ConnectionType::CONNECTION_UNKNOWN;
+  network_connection_tracker_->GetConnectionType(
+      &connection_type,
+      base::BindOnce(&ConnectivityCheckerImpl::OnConnectionChanged,
+                     weak_this_));
+  if (connection_type == network::mojom::ConnectionType::CONNECTION_NONE) {
     return;
+  }
 
-  // If url_request_ is non-null, there is already a check going on. Don't
+  // If url_loader_ is non-null, there is already a check going on. Don't
   // start another.
-  if (url_request_.get())
+  if (url_loader_) {
     return;
+  }
 
-  DVLOG(1) << "Connectivity check: url=" << *connectivity_check_url_;
-  url_request_ = url_request_context_->CreateRequest(
-      *connectivity_check_url_, net::MAXIMUM_PRIORITY, this,
-      MISSING_TRAFFIC_ANNOTATION);
-  url_request_->set_method("HEAD");
-  url_request_->Start();
+  VLOG(1) << "Connectivity check: url=" << *connectivity_check_url_;
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = GURL(*connectivity_check_url_);
+  resource_request->method = "HEAD";
+  resource_request->priority = net::MAXIMUM_PRIORITY;
+  // To enable ssl_info in the response.
+  resource_request->report_raw_headers = true;
 
-  timeout_.Reset(base::Bind(&ConnectivityCheckerImpl::OnUrlRequestTimeout,
-                            this));
+  url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
+                                                 MISSING_TRAFFIC_ANNOTATION);
+  network::SimpleURLLoader::HeadersOnlyCallback callback = base::BindOnce(
+      &ConnectivityCheckerImpl::OnConnectivityCheckComplete, weak_this_);
+  url_loader_->DownloadHeadersOnly(url_loader_factory_.get(),
+                                   std::move(callback));
+
+  timeout_.Reset(
+      base::Bind(&ConnectivityCheckerImpl::OnUrlRequestTimeout, weak_this_));
   // Exponential backoff for timeout in 3, 6 and 12 sec.
   const int timeout = kRequestTimeoutInSeconds
                       << (check_errors_ > 2 ? 2 : check_errors_);
@@ -173,9 +199,9 @@
       FROM_HERE, timeout_.callback(), base::TimeDelta::FromSeconds(timeout));
 }
 
-void ConnectivityCheckerImpl::OnNetworkChanged(
-    net::NetworkChangeNotifier::ConnectionType type) {
-  DVLOG(2) << "OnNetworkChanged " << type;
+void ConnectivityCheckerImpl::OnConnectionChanged(
+    network::mojom::ConnectionType type) {
+  DVLOG(2) << "OnConnectionChanged " << type;
   connection_type_ = type;
 
   if (network_changed_pending_)
@@ -183,15 +209,16 @@
   network_changed_pending_ = true;
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
-      base::BindOnce(&ConnectivityCheckerImpl::OnNetworkChangedInternal, this),
+      base::BindOnce(&ConnectivityCheckerImpl::OnConnectionChangedInternal,
+                     weak_this_),
       base::TimeDelta::FromSeconds(kNetworkChangedDelayInSeconds));
 }
 
-void ConnectivityCheckerImpl::OnNetworkChangedInternal() {
+void ConnectivityCheckerImpl::OnConnectionChangedInternal() {
   network_changed_pending_ = false;
   Cancel();
 
-  if (connection_type_ == net::NetworkChangeNotifier::CONNECTION_NONE) {
+  if (connection_type_ == network::mojom::ConnectionType::CONNECTION_NONE) {
     SetConnected(false);
     return;
   }
@@ -199,18 +226,25 @@
   Check();
 }
 
-void ConnectivityCheckerImpl::OnResponseStarted(net::URLRequest* request,
-                                                int net_error) {
+void ConnectivityCheckerImpl::OnConnectivityCheckComplete(
+    scoped_refptr<net::HttpResponseHeaders> headers) {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  int http_response_code =
-      (net_error == net::OK &&
-       request->response_info().headers.get() != nullptr)
-          ? request->response_info().headers->response_code()
-          : net::HTTP_BAD_REQUEST;
+  DCHECK(url_loader_);
+  timeout_.Cancel();
+  int error = url_loader_->NetError();
+  if (error == net::ERR_INSECURE_RESPONSE && url_loader_->ResponseInfo() &&
+      url_loader_->ResponseInfo()->ssl_info) {
+    LOG(ERROR) << "OnSSLCertificateError: cert_status="
+               << url_loader_->ResponseInfo()->ssl_info->cert_status;
+    OnUrlRequestError(ErrorType::SSL_CERTIFICATE_ERROR);
+    return;
+  }
+  int http_response_code = (error == net::OK && headers)
+                               ? headers->response_code()
+                               : net::HTTP_BAD_REQUEST;
 
   // Clears resources.
-  // URLRequest::Cancel() is called in destructor.
-  url_request_.reset(nullptr);
+  url_loader_.reset(nullptr);
 
   if (http_response_code < 400) {
     DVLOG(1) << "Connectivity check succeeded";
@@ -220,33 +254,12 @@
     // requests. Schedule another check to ensure connectivity hasn't dropped.
     task_runner_->PostDelayedTask(
         FROM_HERE,
-        base::BindOnce(&ConnectivityCheckerImpl::CheckInternal, this),
+        base::BindOnce(&ConnectivityCheckerImpl::CheckInternal, weak_this_),
         base::TimeDelta::FromSeconds(kConnectivitySuccessPeriodSeconds));
-    timeout_.Cancel();
     return;
   }
   LOG(ERROR) << "Connectivity check failed: " << http_response_code;
   OnUrlRequestError(ErrorType::BAD_HTTP_STATUS);
-  timeout_.Cancel();
-}
-
-void ConnectivityCheckerImpl::OnReadCompleted(net::URLRequest* request,
-                                              int bytes_read) {
-  NOTREACHED();
-}
-
-void ConnectivityCheckerImpl::OnSSLCertificateError(
-    net::URLRequest* request,
-    int net_error,
-    const net::SSLInfo& ssl_info,
-    bool fatal) {
-  DCHECK(task_runner_->BelongsToCurrentThread());
-  LOG(ERROR) << "OnSSLCertificateError: cert_status=" << ssl_info.cert_status;
-  url_request_context_->http_transaction_factory()
-      ->GetSession()
-      ->ClearSSLSessionCache();
-  OnUrlRequestError(ErrorType::SSL_CERTIFICATE_ERROR);
-  timeout_.Cancel();
 }
 
 void ConnectivityCheckerImpl::OnUrlRequestError(ErrorType type) {
@@ -262,10 +275,10 @@
     check_errors_ = kNumErrorsToNotifyOffline;
     SetConnected(false);
   }
-  url_request_.reset(nullptr);
+  url_loader_.reset(nullptr);
   // Check again.
   task_runner_->PostDelayedTask(
-      FROM_HERE, base::BindOnce(&ConnectivityCheckerImpl::Check, this),
+      FROM_HERE, base::BindOnce(&ConnectivityCheckerImpl::Check, weak_this_),
       base::TimeDelta::FromSeconds(kConnectivityPeriodSeconds));
 }
 
@@ -277,10 +290,10 @@
 
 void ConnectivityCheckerImpl::Cancel() {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  if (!url_request_.get())
+  if (!url_loader_)
     return;
-  DVLOG(2) << "Cancel connectivity check in progress";
-  url_request_.reset(nullptr);  // URLRequest::Cancel() is called in destructor.
+  VLOG(2) << "Cancel connectivity check in progress";
+  url_loader_.reset(nullptr);
   timeout_.Cancel();
 }
 
diff --git a/chromecast/net/connectivity_checker_impl.h b/chromecast/net/connectivity_checker_impl.h
index 8d7185e..44fb3ca 100644
--- a/chromecast/net/connectivity_checker_impl.h
+++ b/chromecast/net/connectivity_checker_impl.h
@@ -5,24 +5,29 @@
 #ifndef CHROMECAST_NET_CONNECTIVITY_CHECKER_IMPL_H_
 #define CHROMECAST_NET_CONNECTIVITY_CHECKER_IMPL_H_
 
+#include <memory>
+
 #include "base/cancelable_callback.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
 #include "chromecast/net/connectivity_checker.h"
-#include "net/base/network_change_notifier.h"
-#include "net/url_request/url_request.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
 
 class GURL;
 
 namespace base {
 class SingleThreadTaskRunner;
-}
+}  // namespace base
 
 namespace net {
-class SSLInfo;
-class URLRequest;
-class URLRequestContext;
-class URLRequestContextGetter;
-}
+class HttpResponseHeaders;
+}  // namespace net
+
+namespace network {
+class SharedURLLoaderFactory;
+class SimpleURLLoader;
+}  // namespace network
 
 namespace chromecast {
 
@@ -30,13 +35,14 @@
 // to given url.
 class ConnectivityCheckerImpl
     : public ConnectivityChecker,
-      public net::URLRequest::Delegate,
-      public net::NetworkChangeNotifier::NetworkChangeObserver {
+      public network::NetworkConnectionTracker::NetworkConnectionObserver {
  public:
   // Connectivity checking and initialization will run on task_runner.
   static scoped_refptr<ConnectivityCheckerImpl> Create(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-      net::URLRequestContextGetter* url_request_context_getter);
+      std::unique_ptr<network::SharedURLLoaderFactoryInfo>
+          url_loader_factory_info,
+      network::NetworkConnectionTracker* network_connection_tracker);
 
   // ConnectivityChecker implementation:
   bool Connected() const override;
@@ -44,26 +50,23 @@
 
  protected:
   explicit ConnectivityCheckerImpl(
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      network::NetworkConnectionTracker* network_connection_tracker);
   ~ConnectivityCheckerImpl() override;
 
  private:
-  // UrlRequest::Delegate implementation:
-  void OnResponseStarted(net::URLRequest* request, int net_error) override;
-  void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
-  void OnSSLCertificateError(net::URLRequest* request,
-                             int net_error,
-                             const net::SSLInfo& ssl_info,
-                             bool fatal) override;
-
   // Initializes ConnectivityChecker
-  void Initialize(net::URLRequestContextGetter* url_request_context_getter);
+  void Initialize(std::unique_ptr<network::SharedURLLoaderFactoryInfo>
+                      url_loader_factory_info);
 
-  // net::NetworkChangeNotifier::NetworkChangeObserver implementation:
-  void OnNetworkChanged(
-      net::NetworkChangeNotifier::ConnectionType type) override;
+  // network::NetworkConnectionTracker::NetworkConnectionObserver
+  // implementation:
+  void OnConnectionChanged(network::mojom::ConnectionType type) override;
 
-  void OnNetworkChangedInternal();
+  void OnConnectionChangedInternal();
+
+  void OnConnectivityCheckComplete(
+      scoped_refptr<net::HttpResponseHeaders> headers);
 
   // Cancels current connectivity checking in progress.
   void Cancel();
@@ -86,17 +89,17 @@
   void CheckInternal();
 
   std::unique_ptr<GURL> connectivity_check_url_;
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
-  net::URLRequestContext* url_request_context_;
-  std::unique_ptr<net::URLRequest> url_request_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+  std::unique_ptr<network::SimpleURLLoader> url_loader_;
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  network::NetworkConnectionTracker* const network_connection_tracker_;
 
   // connected_lock_ protects access to connected_ which is shared across
   // threads.
   mutable base::Lock connected_lock_;
   bool connected_;
 
-  net::NetworkChangeNotifier::ConnectionType connection_type_;
+  network::mojom::ConnectionType connection_type_;
   // Number of connectivity check errors.
   unsigned int check_errors_;
   bool network_changed_pending_;
@@ -105,6 +108,9 @@
   // called.
   base::CancelableCallback<void()> timeout_;
 
+  base::WeakPtr<ConnectivityCheckerImpl> weak_this_;
+  base::WeakPtrFactory<ConnectivityCheckerImpl> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(ConnectivityCheckerImpl);
 };
 
diff --git a/chromecast/net/fake_connectivity_checker.cc b/chromecast/net/fake_connectivity_checker.cc
index fc3caed..cbe0514 100644
--- a/chromecast/net/fake_connectivity_checker.cc
+++ b/chromecast/net/fake_connectivity_checker.cc
@@ -3,13 +3,13 @@
 // found in the LICENSE file.
 
 #include "chromecast/net/fake_connectivity_checker.h"
+#include "base/threading/thread_task_runner_handle.h"
 
 namespace chromecast {
 
 FakeConnectivityChecker::FakeConnectivityChecker()
-    : ConnectivityChecker(),
-      connected_(true) {
-}
+    : ConnectivityChecker(base::ThreadTaskRunnerHandle::Get()),
+      connected_(true) {}
 
 FakeConnectivityChecker::~FakeConnectivityChecker() {}
 
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 0e5e7ea..91dbfc2 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-12579.0.0
\ No newline at end of file
+12581.0.0
\ No newline at end of file
diff --git a/chromeos/dbus/power/fake_power_manager_client.cc b/chromeos/dbus/power/fake_power_manager_client.cc
index 46f6f1a..17f15c8 100644
--- a/chromeos/dbus/power/fake_power_manager_client.cc
+++ b/chromeos/dbus/power/fake_power_manager_client.cc
@@ -279,6 +279,10 @@
   --num_pending_suspend_readiness_callbacks_;
 }
 
+bool FakePowerManagerClient::SupportsAmbientColor() {
+  return supports_ambient_color_;
+}
+
 void FakePowerManagerClient::CreateArcTimers(
     const std::string& tag,
     std::vector<std::pair<clockid_t, base::ScopedFD>> arc_timer_requests,
diff --git a/chromeos/dbus/power/fake_power_manager_client.h b/chromeos/dbus/power/fake_power_manager_client.h
index 41954f9..7ee82d23 100644
--- a/chromeos/dbus/power/fake_power_manager_client.h
+++ b/chromeos/dbus/power/fake_power_manager_client.h
@@ -118,6 +118,7 @@
   void BlockSuspend(const base::UnguessableToken& token,
                     const std::string& debug_info) override;
   void UnblockSuspend(const base::UnguessableToken& token) override;
+  bool SupportsAmbientColor() override;
   void CreateArcTimers(
       const std::string& tag,
       std::vector<std::pair<clockid_t, base::ScopedFD>> arc_timer_requests,
@@ -190,6 +191,10 @@
     keyboard_brightness_percent_ = percent;
   }
 
+  void set_supports_ambient_color(bool supports_ambient_color) {
+    supports_ambient_color_ = supports_ambient_color;
+  }
+
   // Sets |tick_clock| to |tick_clock_|.
   void set_tick_clock(const base::TickClock* tick_clock) {
     tick_clock_ = tick_clock;
@@ -255,6 +260,10 @@
   // explicitly by calling ApplyPendingScreenBrightnessChange().
   bool enqueue_brightness_changes_on_backlights_forced_off_ = false;
 
+  // Whether the device has an ambient color sensor. Can be set via
+  // SetSupportsAmbientColor().
+  bool supports_ambient_color_ = false;
+
   // Pending screen brightness changes caused by SetBacklightsForcedOff().
   // ApplyPendingScreenBrightnessChange() applies the first pending change.
   std::queue<power_manager::BacklightBrightnessChange>
diff --git a/chromeos/dbus/power/fake_power_manager_client_unittest.cc b/chromeos/dbus/power/fake_power_manager_client_unittest.cc
index 78b2271a..6b598db 100644
--- a/chromeos/dbus/power/fake_power_manager_client_unittest.cc
+++ b/chromeos/dbus/power/fake_power_manager_client_unittest.cc
@@ -134,4 +134,13 @@
   EXPECT_FALSE(client.HasObserver(&test_observer));
 }
 
+TEST(FakePowerManagerClientTest, AmbientColorSupport) {
+  FakePowerManagerClient client;
+  EXPECT_FALSE(client.SupportsAmbientColor());
+  client.set_supports_ambient_color(true);
+  EXPECT_TRUE(client.SupportsAmbientColor());
+  client.set_supports_ambient_color(false);
+  EXPECT_FALSE(client.SupportsAmbientColor());
+}
+
 }  // namespace chromeos
diff --git a/chromeos/dbus/power/power_manager_client.cc b/chromeos/dbus/power/power_manager_client.cc
index fa24ab71..213e531 100644
--- a/chromeos/dbus/power/power_manager_client.cc
+++ b/chromeos/dbus/power/power_manager_client.cc
@@ -211,6 +211,7 @@
 
     RegisterSuspendDelays();
     RequestStatusUpdate();
+    CheckAmbientColorSupport();
   }
 
   // PowerManagerClient overrides:
@@ -481,6 +482,10 @@
     MaybeReportSuspendReadiness();
   }
 
+  bool SupportsAmbientColor() override {
+    return device_supports_ambient_color_;
+  }
+
   void CreateArcTimers(
       const std::string& tag,
       std::vector<std::pair<clockid_t, base::ScopedFD>> arc_timer_requests,
@@ -747,6 +752,31 @@
     std::move(callback).Run(state);
   }
 
+  void CheckAmbientColorSupport() {
+    dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
+                                 power_manager::kHasAmbientColorDeviceMethod);
+    power_manager_proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&PowerManagerClientImpl::OnHasAmbientColorDevice,
+                       weak_ptr_factory_.GetWeakPtr()));
+  }
+
+  void OnHasAmbientColorDevice(dbus::Response* response) {
+    if (!response) {
+      device_supports_ambient_color_ = false;
+      return;
+    }
+    dbus::MessageReader reader(response);
+    bool is_supported = false;
+    if (!reader.PopBool(&is_supported)) {
+      POWER_LOG(ERROR) << "Error reading response from powerd: "
+                       << response->ToString();
+      device_supports_ambient_color_ = false;
+      return;
+    }
+    device_supports_ambient_color_ = is_supported;
+  }
+
   void OnGetSwitchStates(DBusMethodCallback<SwitchStates> callback,
                          dbus::Response* response) {
     if (!response) {
@@ -1162,6 +1192,10 @@
   // Last state passed to SetIsProjecting().
   bool last_is_projecting_ = false;
 
+  // Whether the device supports ambient color. This value is checked when the
+  // DBUS service starts and is cached.
+  bool device_supports_ambient_color_ = false;
+
   // The last proto received from D-Bus; initially empty.
   base::Optional<power_manager::PowerSupplyProperties> proto_;
 
diff --git a/chromeos/dbus/power/power_manager_client.h b/chromeos/dbus/power/power_manager_client.h
index cfbb078..72a95126 100644
--- a/chromeos/dbus/power/power_manager_client.h
+++ b/chromeos/dbus/power/power_manager_client.h
@@ -291,6 +291,9 @@
   // ready for a suspend.
   virtual void UnblockSuspend(const base::UnguessableToken& token) = 0;
 
+  // Whether the device supports Ambient color.
+  virtual bool SupportsAmbientColor() = 0;
+
   // Creates timers corresponding to clocks present in |arc_timer_requests|.
   // ScopedFDs are used to indicate timer expiration as described in
   // |StartArcTimer|. Aysnchronously runs |callback| with the created timers'
diff --git a/chromeos/dbus/power/power_manager_client_unittest.cc b/chromeos/dbus/power/power_manager_client_unittest.cc
index be96eaf..7bc2e89 100644
--- a/chromeos/dbus/power/power_manager_client_unittest.cc
+++ b/chromeos/dbus/power/power_manager_client_unittest.cc
@@ -241,6 +241,11 @@
         *proxy_,
         DoCallMethod(HasMember(power_manager::kGetPowerSupplyPropertiesMethod),
                      _, _));
+    // Init will test for the presence of an ambient light sensor.
+    EXPECT_CALL(
+        *proxy_,
+        DoCallMethod(HasMember(power_manager::kHasAmbientColorDeviceMethod), _,
+                     _));
 
     PowerManagerClient::Initialize(bus_.get());
     client_ = PowerManagerClient::Get();
diff --git a/chromeos/dbus/upstart/fake_upstart_client.cc b/chromeos/dbus/upstart/fake_upstart_client.cc
index a8b524c..2065e54 100644
--- a/chromeos/dbus/upstart/fake_upstart_client.cc
+++ b/chromeos/dbus/upstart/fake_upstart_client.cc
@@ -40,14 +40,14 @@
                                  const std::vector<std::string>& upstart_env,
                                  VoidDBusMethodCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), true));
+      FROM_HERE, base::BindOnce(std::move(callback), start_job_result_));
 }
 
 void FakeUpstartClient::StopJob(const std::string& job,
                                 const std::vector<std::string>& upstart_env,
                                 VoidDBusMethodCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), true));
+      FROM_HERE, base::BindOnce(std::move(callback), stop_job_result_));
 }
 
 void FakeUpstartClient::StartAuthPolicyService() {
diff --git a/chromeos/dbus/upstart/fake_upstart_client.h b/chromeos/dbus/upstart/fake_upstart_client.h
index 73cc8bd..eb3d7f5 100644
--- a/chromeos/dbus/upstart/fake_upstart_client.h
+++ b/chromeos/dbus/upstart/fake_upstart_client.h
@@ -41,7 +41,13 @@
   void StartWilcoDtcService(VoidDBusMethodCallback callback) override;
   void StopWilcoDtcService(VoidDBusMethodCallback callback) override;
 
+  void set_start_job_result(bool result) { start_job_result_ = result; }
+  void set_stop_job_result(bool result) { stop_job_result_ = result; }
+
  private:
+  bool start_job_result_ = true;
+  bool stop_job_result_ = true;
+
   DISALLOW_COPY_AND_ASSIGN(FakeUpstartClient);
 };
 
diff --git a/chromeos/ime/input_methods.txt b/chromeos/ime/input_methods.txt
index 149897e..81801f95 100644
--- a/chromeos/ime/input_methods.txt
+++ b/chromeos/ime/input_methods.txt
@@ -86,7 +86,7 @@
 xkb:cz:qwerty:cze     cz(qwerty)     cs        CS login
 xkb:ee::est           ee             et        EE login
 xkb:es::spa           es             es        ES login
-xkb:es:cat:cat        es(cat)        ca        CAS login
+xkb:es:cat:cat        es(cat)        ca        CAT login
 xkb:dk::dan           dk             da        DK login
 xkb:fo::fao           fo             fo        FO
 xkb:gr::gre           gr             el        GR
diff --git a/chromeos/services/ime/ime_service_unittest.cc b/chromeos/services/ime/ime_service_unittest.cc
index 6eef9942..f826050 100644
--- a/chromeos/services/ime/ime_service_unittest.cc
+++ b/chromeos/services/ime/ime_service_unittest.cc
@@ -29,11 +29,6 @@
   *success = result;
 }
 
-void TestProcessTextCallback(std::string* res_out,
-                             const std::string& response) {
-  *res_out = response;
-}
-
 void TestProcessKeypressForRulebasedCallback(
     mojom::KeypressResponseForRulebased* res_out,
     mojom::KeypressResponseForRulebasedPtr response) {
@@ -115,182 +110,6 @@
   EXPECT_FALSE(success);
 }
 
-TEST_F(ImeServiceTest, MultipleClients) {
-  bool success = false;
-  TestClientChannel test_channel_1;
-  TestClientChannel test_channel_2;
-  mojo::Remote<mojom::InputChannel> remote_engine_1;
-  mojo::Remote<mojom::InputChannel> remote_engine_2;
-
-  remote_manager_->ConnectToImeEngine(
-      "m17n:ar", remote_engine_1.BindNewPipeAndPassReceiver(),
-      test_channel_1.CreatePendingRemote(), extra,
-      base::BindOnce(&ConnectCallback, &success));
-  remote_manager_.FlushForTesting();
-
-  remote_manager_->ConnectToImeEngine(
-      "m17n:ar", remote_engine_2.BindNewPipeAndPassReceiver(),
-      test_channel_2.CreatePendingRemote(), extra,
-      base::BindOnce(&ConnectCallback, &success));
-  remote_manager_.FlushForTesting();
-
-  std::string response;
-  std::string process_text_key =
-      "{\"method\":\"keyEvent\",\"type\":\"keydown\""
-      ",\"code\":\"KeyA\",\"shift\":true,\"altgr\":false,\"caps\":false}";
-  remote_engine_1->ProcessText(
-      process_text_key, base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine_1.FlushForTesting();
-
-  remote_engine_2->ProcessText(
-      process_text_key, base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine_2.FlushForTesting();
-
-  std::string process_text_key_count = "{\"method\":\"countKey\"}";
-  remote_engine_1->ProcessText(
-      process_text_key_count,
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine_1.FlushForTesting();
-  EXPECT_EQ("1", response);
-
-  remote_engine_2->ProcessText(
-      process_text_key_count,
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine_2.FlushForTesting();
-  EXPECT_EQ("1", response);
-}
-
-// Tests that the rule-based Arabic keyboard can work correctly.
-TEST_F(ImeServiceTest, RuleBasedArabic) {
-  bool success = false;
-  TestClientChannel test_channel;
-  mojo::Remote<mojom::InputChannel> remote_engine;
-
-  remote_manager_->ConnectToImeEngine(
-      "m17n:ar", remote_engine.BindNewPipeAndPassReceiver(),
-      test_channel.CreatePendingRemote(), extra,
-      base::BindOnce(&ConnectCallback, &success));
-  remote_manager_.FlushForTesting();
-  EXPECT_TRUE(success);
-
-  // Test Shift+KeyA.
-  std::string response;
-  remote_engine->ProcessText(
-      "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"KeyA\","
-      "\"shift\":true,\"altgr\":false,\"caps\":false}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine.FlushForTesting();
-  const wchar_t* expected_response =
-      L"{\"result\":true,\"operations\":[{\"method\":\"commitText\","
-      L"\"arguments\":[\"\u0650\"]}]}";
-  EXPECT_EQ(base::WideToUTF8(expected_response), response);
-
-  // Test KeyB.
-  remote_engine->ProcessText(
-      "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"KeyB\","
-      "\"shift\":false,\"altgr\":false,\"caps\":false}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine.FlushForTesting();
-  expected_response =
-      L"{\"result\":true,\"operations\":[{\"method\":\"commitText\","
-      L"\"arguments\":[\"\u0644\u0627\"]}]}";
-  EXPECT_EQ(base::WideToUTF8(expected_response), response);
-
-  // Test unhandled key.
-  remote_engine->ProcessText(
-      "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"Enter\","
-      "\"shift\":false,\"altgr\":false,\"caps\":false}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine.FlushForTesting();
-  EXPECT_EQ("{\"result\":false}", response);
-
-  // Test keyup.
-  remote_engine->ProcessText(
-      "{\"method\":\"keyEvent\",\"type\":\"keyup\",\"code\":\"Enter\","
-      "\"shift\":false,\"altgr\":false,\"caps\":false}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine.FlushForTesting();
-  EXPECT_EQ("{\"result\":false}", response);
-
-  // Test reset.
-  remote_engine->ProcessText(
-      "{\"method\":\"reset\"}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine.FlushForTesting();
-  EXPECT_EQ("{\"result\":true}", response);
-
-  // Test invalid request.
-  remote_engine->ProcessText(
-      "{\"method\":\"keyEvent\",\"type\":\"keydown\"}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine.FlushForTesting();
-  EXPECT_EQ("{\"result\":false}", response);
-}
-
-// Tests that the rule-based DevaPhone keyboard can work correctly.
-TEST_F(ImeServiceTest, RuleBasedDevaPhone) {
-  bool success = false;
-  TestClientChannel test_channel;
-  mojo::Remote<mojom::InputChannel> remote_engine;
-
-  remote_manager_->ConnectToImeEngine(
-      "m17n:deva_phone", remote_engine.BindNewPipeAndPassReceiver(),
-      test_channel.CreatePendingRemote(), extra,
-      base::BindOnce(&ConnectCallback, &success));
-  remote_manager_.FlushForTesting();
-  EXPECT_TRUE(success);
-
-  std::string response;
-
-  // KeyN.
-  remote_engine->ProcessText(
-      "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"KeyN\","
-      "\"shift\":false,\"altgr\":false,\"caps\":false}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine.FlushForTesting();
-  const char* expected_response =
-      u8"{\"result\":true,\"operations\":[{\"method\":\"setComposition\","
-      u8"\"arguments\":[\"\u0928\"]}]}";
-  EXPECT_EQ(expected_response, response);
-
-  // Backspace.
-  remote_engine->ProcessText(
-      "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"Backspace\","
-      "\"shift\":false,\"altgr\":false,\"caps\":false}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine.FlushForTesting();
-  expected_response =
-      u8"{\"result\":true,\"operations\":[{\"method\":\"setComposition\","
-      u8"\"arguments\":[\"\"]}]}";
-  EXPECT_EQ(expected_response, response);
-
-  // KeyN + KeyC.
-  remote_engine->ProcessText(
-      "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"KeyN\","
-      "\"shift\":false,\"altgr\":false,\"caps\":false}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine->ProcessText(
-      "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"KeyC\","
-      "\"shift\":false,\"altgr\":false,\"caps\":false}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine.FlushForTesting();
-  expected_response =
-      u8"{\"result\":true,\"operations\":[{\"method\":\"setComposition\","
-      u8"\"arguments\":[\"\u091e\u094d\u091a\"]}]}";
-  EXPECT_EQ(expected_response, response);
-
-  // Space.
-  remote_engine->ProcessText(
-      "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"Space\","
-      "\"shift\":false,\"altgr\":false,\"caps\":false}",
-      base::BindOnce(&TestProcessTextCallback, &response));
-  remote_engine.FlushForTesting();
-  expected_response =
-      u8"{\"result\":true,\"operations\":[{\"method\":\"commitText\","
-      u8"\"arguments\":[\"\u091e\u094d\u091a \"]}]}";
-  EXPECT_EQ(expected_response, response);
-}
-
 TEST_F(ImeServiceTest, MultipleClientsRulebased) {
   bool success = false;
   TestClientChannel test_channel_1;
@@ -339,13 +158,13 @@
 }
 
 // Tests that the rule-based Arabic keyboard can work correctly.
-TEST_F(ImeServiceTest, RuleBasedArabicKeypress) {
+TEST_F(ImeServiceTest, RuleBasedArabic) {
   bool success = false;
   TestClientChannel test_channel;
-  mojom::InputChannelPtr to_engine_ptr;
+  mojo::Remote<mojom::InputChannel> to_engine_remote;
 
   remote_manager_->ConnectToImeEngine(
-      "m17n:ar", mojo::MakeRequest(&to_engine_ptr),
+      "m17n:ar", to_engine_remote.BindNewPipeAndPassReceiver(),
       test_channel.CreatePendingRemote(), extra,
       base::BindOnce(&ConnectCallback, &success));
   remote_manager_.FlushForTesting();
@@ -353,11 +172,11 @@
 
   // Test Shift+KeyA.
   mojom::KeypressResponseForRulebased response;
-  to_engine_ptr->ProcessKeypressForRulebased(
+  to_engine_remote->ProcessKeypressForRulebased(
       mojom::KeypressInfoForRulebased::New("keydown", "KeyA", true, false,
                                            false, false, false),
       base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  to_engine_remote.FlushForTesting();
 
   EXPECT_EQ(response.result, true);
   std::vector<mojom::OperationForRulebasedPtr> expected_operations;
@@ -367,11 +186,11 @@
   EXPECT_EQ(response.operations, expected_operations);
 
   // Test KeyB
-  to_engine_ptr->ProcessKeypressForRulebased(
+  to_engine_remote->ProcessKeypressForRulebased(
       mojom::KeypressInfoForRulebased::New("keydown", "KeyB", false, false,
                                            false, false, false),
       base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  to_engine_remote.FlushForTesting();
   EXPECT_EQ(response.result, true);
   expected_operations = std::vector<mojom::OperationForRulebasedPtr>(0);
   expected_operations.push_back({mojom::OperationForRulebased::New(
@@ -380,41 +199,41 @@
   EXPECT_EQ(response.operations, expected_operations);
 
   // Test unhandled key.
-  to_engine_ptr->ProcessKeypressForRulebased(
+  to_engine_remote->ProcessKeypressForRulebased(
       mojom::KeypressInfoForRulebased::New("keydown", "Enter", false, false,
                                            false, false, false),
       base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  to_engine_remote.FlushForTesting();
   EXPECT_EQ(response.result, false);
 
   // Test keyup.
-  to_engine_ptr->ProcessKeypressForRulebased(
+  to_engine_remote->ProcessKeypressForRulebased(
       mojom::KeypressInfoForRulebased::New("keyup", "Enter", false, false,
                                            false, false, false),
       base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  to_engine_remote.FlushForTesting();
   EXPECT_EQ(response.result, false);
 
   // TODO(keithlee) Test reset function
-  to_engine_ptr->ResetForRulebased();
+  to_engine_remote->ResetForRulebased();
 
   // Test invalid request.
-  to_engine_ptr->ProcessKeypressForRulebased(
+  to_engine_remote->ProcessKeypressForRulebased(
       mojom::KeypressInfoForRulebased::New("keydown", "", false, false, false,
                                            false, false),
       base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  to_engine_remote.FlushForTesting();
   EXPECT_EQ(response.result, false);
 }
 
 // Tests that the rule-based DevaPhone keyboard can work correctly.
-TEST_F(ImeServiceTest, RuleBasedDevaPhoneKeypress) {
+TEST_F(ImeServiceTest, RuleBasedDevaPhone) {
   bool success = false;
   TestClientChannel test_channel;
-  mojom::InputChannelPtr to_engine_ptr;
+  mojo::Remote<mojom::InputChannel> to_engine_remote;
 
   remote_manager_->ConnectToImeEngine(
-      "m17n:deva_phone", mojo::MakeRequest(&to_engine_ptr),
+      "m17n:deva_phone", to_engine_remote.BindNewPipeAndPassReceiver(),
       test_channel.CreatePendingRemote(), extra,
       base::BindOnce(&ConnectCallback, &success));
   remote_manager_.FlushForTesting();
@@ -424,11 +243,11 @@
   std::vector<mojom::OperationForRulebasedPtr> expected_operations;
 
   // Test KeyN.
-  to_engine_ptr->ProcessKeypressForRulebased(
+  to_engine_remote->ProcessKeypressForRulebased(
       mojom::KeypressInfoForRulebased::New("keydown", "KeyN", false, false,
                                            false, false, false),
       base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  to_engine_remote.FlushForTesting();
 
   EXPECT_EQ(response.result, true);
   expected_operations = std::vector<mojom::OperationForRulebasedPtr>(0);
@@ -438,11 +257,11 @@
   EXPECT_EQ(response.operations, expected_operations);
 
   // Backspace.
-  to_engine_ptr->ProcessKeypressForRulebased(
+  to_engine_remote->ProcessKeypressForRulebased(
       mojom::KeypressInfoForRulebased::New("keydown", "Backspace", false, false,
                                            false, false, false),
       base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  to_engine_remote.FlushForTesting();
 
   EXPECT_EQ(response.result, true);
   expected_operations = std::vector<mojom::OperationForRulebasedPtr>(0);
@@ -452,15 +271,15 @@
   EXPECT_EQ(response.operations, expected_operations);
 
   // KeyN + KeyC.
-  to_engine_ptr->ProcessKeypressForRulebased(
+  to_engine_remote->ProcessKeypressForRulebased(
       mojom::KeypressInfoForRulebased::New("keydown", "KeyN", false, false,
                                            false, false, false),
       base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response));
-  to_engine_ptr->ProcessKeypressForRulebased(
+  to_engine_remote->ProcessKeypressForRulebased(
       mojom::KeypressInfoForRulebased::New("keydown", "KeyC", false, false,
                                            false, false, false),
       base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  to_engine_remote.FlushForTesting();
 
   EXPECT_EQ(response.result, true);
   expected_operations = std::vector<mojom::OperationForRulebasedPtr>(0);
@@ -471,11 +290,11 @@
   EXPECT_EQ(response.operations, expected_operations);
 
   // Space.
-  to_engine_ptr->ProcessKeypressForRulebased(
+  to_engine_remote->ProcessKeypressForRulebased(
       mojom::KeypressInfoForRulebased::New("keydown", "Space", false, false,
                                            false, false, false),
       base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  to_engine_remote.FlushForTesting();
 
   EXPECT_EQ(response.result, true);
   expected_operations = std::vector<mojom::OperationForRulebasedPtr>(0);
diff --git a/chromeos/services/ime/input_engine.cc b/chromeos/services/ime/input_engine.cc
index 7161352..0b0ecc1 100644
--- a/chromeos/services/ime/input_engine.cc
+++ b/chromeos/services/ime/input_engine.cc
@@ -100,9 +100,7 @@
 
 void InputEngine::ProcessText(const std::string& message,
                               ProcessTextCallback callback) {
-  auto& context = channel_receivers_.current_context();
-  std::string result = Process(message, context.get());
-  std::move(callback).Run(result);
+  NOTIMPLEMENTED();  // Text message not used in the rulebased engine.
 }
 
 void InputEngine::ProcessMessage(const std::vector<uint8_t>& message,
@@ -110,118 +108,6 @@
   NOTIMPLEMENTED();  // Protobuf message is not used in the rulebased engine.
 }
 
-std::string InputEngine::Process(const std::string& message,
-                                 const InputEngineContext* context) {
-  auto& engine = context->engine;
-  if (!engine)
-    return std::string();
-
-  const char kFalseResponse[] = "{\"result\":false}";
-
-  // The request message is in JSON format as:
-  // {
-  //   'method': <string>,  // 'reset' or 'keyEvent'
-  //   'type': <string>,    // 'keydown' or 'keyup'
-  //   'code': <string>,    // e.g. 'KeyA', 'Backspace', etc.
-  //   'shift': <boolean>,
-  //   'altgr': <boolean>,
-  //   'caps': <boolean>,
-  //   'ctrl': <boolean>,
-  //   'alt': <boolean>
-  // }
-  // TODO(shuchen): make parser/writer util class for the JSON-based protocol.
-  int error_code;
-  std::string error_string;
-  std::unique_ptr<base::Value> message_value =
-      base::JSONReader::ReadAndReturnErrorDeprecated(
-          message, base::JSON_PARSE_RFC, &error_code, &error_string);
-  if (!message_value) {
-    LOG(ERROR) << "Read message error: " << error_code << "; " << error_string;
-    return kFalseResponse;
-  }
-  base::Value* method = message_value->FindKey("method");
-  if (!method)
-    return kFalseResponse;
-
-  const std::string& method_str = method->GetString();
-  if (method_str == "countKey") {
-    return std::to_string(engine->process_key_count());
-  }
-
-  if (method_str == "reset") {
-    engine->Reset();
-    return "{\"result\":true}";
-  }
-
-  if (method_str == "keyEvent") {
-    base::Value* type = message_value->FindKey("type");
-    if (!type || type->GetString() != "keydown")
-      return kFalseResponse;
-  }
-
-  base::Value* code = message_value->FindKey("code");
-  base::Value* shift = message_value->FindKey("shift");
-  base::Value* altgr = message_value->FindKey("altgr");
-  base::Value* caps = message_value->FindKey("caps");
-  if (!code || !shift || !altgr || !caps)
-    return kFalseResponse;
-
-  uint8_t modifiers = 0;
-  if (shift->GetBool())
-    modifiers |= rulebased::MODIFIER_SHIFT;
-  if (altgr->GetBool())
-    modifiers |= rulebased::MODIFIER_ALTGR;
-  if (caps->GetBool())
-    modifiers |= rulebased::MODIFIER_CAPSLOCK;
-
-  rulebased::ProcessKeyResult res =
-      engine->ProcessKey(code->GetString(), modifiers);
-
-  // The response message is in JSON format as:
-  // {
-  //   'result': <boolean>,
-  //   'operations': [
-  //     {
-  //       'method': 'commitText|setComposition',
-  //       'arguments': <string>
-  //     }
-  //   ]
-  // }
-  std::string response_str = "{\"result\":";
-  response_str += (res.key_handled ? "true" : "false");
-  std::vector<std::string> ops;
-  if (!res.commit_text.empty()) {
-    std::string commit_text;
-    base::EscapeJSONString(res.commit_text, false, &commit_text);
-    ops.push_back("{\"method\":\"commitText\",\"arguments\":[\"" + commit_text +
-                  "\"]}");
-  }
-  // Need to add the setComposition operation to the result when the key is
-  // handled and commit_text and composition_text are both empty.
-  // That is the case of using Backspace to delete the last character in
-  // composition.
-  if (!res.composition_text.empty() ||
-      (res.key_handled && res.commit_text.empty())) {
-    std::string composition_text;
-    base::EscapeJSONString(res.composition_text, false, &composition_text);
-    ops.push_back("{\"method\":\"setComposition\",\"arguments\":[\"" +
-                  composition_text + "\"]}");
-  }
-  if (ops.empty()) {
-    response_str += "}";
-  } else {
-    response_str += ",\"operations\":[";
-    for (size_t i = 0; i < ops.size(); ++i) {
-      if (i > 0)
-        response_str += ",";
-      response_str += ops[i];
-    }
-    response_str += "]}";
-  }
-
-  return response_str;
-}
-
 void InputEngine::ProcessKeypressForRulebased(
     mojom::KeypressInfoForRulebasedPtr keypress_info,
     ProcessKeypressForRulebasedCallback callback) {
diff --git a/chromeos/services/ime/input_engine.h b/chromeos/services/ime/input_engine.h
index 088d650..edd94965 100644
--- a/chromeos/services/ime/input_engine.h
+++ b/chromeos/services/ime/input_engine.h
@@ -60,9 +60,6 @@
   // Returns whether the given ime_spec is supported by rulebased engine.
   bool IsImeSupportedByRulebased(const std::string& ime_spec);
 
-  std::string Process(const std::string& message,
-                      const InputEngineContext* context);
-
   mojo::ReceiverSet<mojom::InputChannel, std::unique_ptr<InputEngineContext>>
       channel_receivers_;
 
diff --git a/components/arc/mojom/intent_helper.mojom b/components/arc/mojom/intent_helper.mojom
index 2de5ddb..c1c6e86 100644
--- a/components/arc/mojom/intent_helper.mojom
+++ b/components/arc/mojom/intent_helper.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 30
+// Next MinVersion: 31
 
 module arc.mojom;
 
@@ -50,6 +50,12 @@
   int32 port;
 };
 
+struct UriComponents {
+  string scheme; // Scheme to create URI in ARC.
+  string authority; // Authority to create URI in ARC.
+  string path; // Path to create URI in ARC.
+};
+
 struct IntentInfo {
   string action;
   array<string>? categories;
@@ -62,6 +68,10 @@
   // intents to carry additional data. See:
   // https://developer.android.com/reference/android/content/Intent#putExtra(java.lang.String,%20java.lang.String)
   [MinVersion=22] map<string, string>? extras;
+
+  // Optional URI components to build data URI in ARC. If |IntentInfo.data| is
+  // set, this field will be ignored.
+  [MinVersion=30] UriComponents? uri_components;
 };
 
 struct IntentFilter {
@@ -174,7 +184,7 @@
 
 // Handles intents from ARC in Chrome.
 // Deprecated method ID: 4
-// Next method ID: 13
+// Next method ID: 14
 interface IntentHelperHost {
   // Called when icons associated with the package are no longer up to date.
   [MinVersion=3] OnIconInvalidated@1(string package_name);
diff --git a/components/arc/session/arc_vm_client_adapter.cc b/components/arc/session/arc_vm_client_adapter.cc
index cec142fd..7cb7527 100644
--- a/components/arc/session/arc_vm_client_adapter.cc
+++ b/components/arc/session/arc_vm_client_adapter.cc
@@ -25,6 +25,8 @@
 namespace arc {
 namespace {
 
+constexpr const char kArcVmServerProxyJobName[] = "arcvm_2dserver_2dproxy";
+
 chromeos::ConciergeClient* GetConciergeClient() {
   return chromeos::DBusThreadManager::Get()->GetConciergeClient();
 }
@@ -88,6 +90,12 @@
 
   void UpgradeArc(const UpgradeArcContainerRequest& request,
                   chromeos::VoidDBusMethodCallback callback) override {
+    VLOG(1) << "Starting arcvm-server-proxy";
+    chromeos::UpstartClient::Get()->StartJob(
+        kArcVmServerProxyJobName, /*environment=*/{},
+        base::BindOnce(&ArcVmClientAdapter::OnArcVmServerProxyJobStarted,
+                       weak_factory_.GetWeakPtr()));
+
     VLOG(1) << "Starting ARCVM";
     std::vector<std::string> env{
         {"USER_ID_HASH=" + user_id_hash_},
@@ -129,7 +137,15 @@
 
  private:
   void OnArcInstanceStopped() {
-    VLOG(1) << "arcvm stopped.";
+    VLOG(1) << "ARCVM stopped. Stopping arcvm-server-proxy";
+
+    // TODO(yusukes): Consider removing this stop call once b/142140355 is
+    // implemented.
+    chromeos::UpstartClient::Get()->StopJob(
+        kArcVmServerProxyJobName, /*environment=*/{},
+        base::BindOnce(&ArcVmClientAdapter::OnArcVmServerProxyJobStopped,
+                       weak_factory_.GetWeakPtr()));
+
     for (auto& observer : observer_list_)
       observer.ArcInstanceStopped();
   }
@@ -140,6 +156,14 @@
       LOG(ERROR) << "Failed to stop arcvm.";
   }
 
+  void OnArcVmServerProxyJobStarted(bool result) {
+    VLOG(1) << "OnArcVmServerProxyJobStarted result=" << result;
+  }
+
+  void OnArcVmServerProxyJobStopped(bool result) {
+    VLOG(1) << "OnArcVmServerProxyJobStopped result=" << result;
+  }
+
   // A hash of the primary profile user ID.
   std::string user_id_hash_;
 
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index 65f42c9c..89be0f6 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -219,8 +219,7 @@
   if (form_util::FindFormAndFieldForFormControlElement(element_, &form,
                                                        &field)) {
     GetAutofillDriver()->TextFieldDidScroll(
-        form, field,
-        render_frame()->GetRenderView()->ElementBoundsInWindow(element_));
+        form, field, render_frame()->ElementBoundsInWindow(element_));
   }
 
   // Ignore subsequent scroll offset changes.
@@ -269,8 +268,7 @@
   if (form_util::FindFormAndFieldForFormControlElement(element_, &form,
                                                        &field)) {
     GetAutofillDriver()->FocusOnFormField(
-        form, field,
-        render_frame()->GetRenderView()->ElementBoundsInWindow(element_));
+        form, field, render_frame()->ElementBoundsInWindow(element_));
   }
 }
 
@@ -351,8 +349,7 @@
   if (form_util::FindFormAndFieldForFormControlElement(element, &form,
                                                        &field)) {
     GetAutofillDriver()->TextFieldDidChange(
-        form, field,
-        render_frame()->GetRenderView()->ElementBoundsInWindow(element),
+        form, field, render_frame()->ElementBoundsInWindow(element),
         base::TimeTicks::Now());
   }
 }
@@ -772,7 +769,7 @@
   GetAutofillDriver()->SetDataList(data_list_values, data_list_labels);
   GetAutofillDriver()->QueryFormFieldAutofill(
       autofill_query_id_, form, field,
-      render_frame()->GetRenderView()->ElementBoundsInWindow(element_),
+      render_frame()->ElementBoundsInWindow(element_),
       autoselect_first_suggestion);
 }
 
@@ -993,8 +990,7 @@
       if (form_util::FindFormAndFieldForFormControlElement(element, &form,
                                                            &field)) {
         GetAutofillDriver()->SelectControlDidChange(
-            form, field,
-            render_frame()->GetRenderView()->ElementBoundsInWindow(element));
+            form, field, render_frame()->ElementBoundsInWindow(element));
       }
     }
   }
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index 88ff0eaf..7a3b7cf6 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1305,7 +1305,7 @@
 
   GetPasswordManagerDriver()->ShowPasswordSuggestions(
       field.text_direction, username_string, options,
-      render_frame()->GetRenderView()->ElementBoundsInWindow(user_input));
+      render_frame()->ElementBoundsInWindow(user_input));
   username_query_prefix_ = username_string;
   return CanShowSuggestion(password_info.fill_data, username_string, show_all);
 }
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index 5aafec20..60b2413 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -309,7 +309,7 @@
     LogMessage(Logger::STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP);
     autofill::password_generation::PasswordGenerationUIData
         password_generation_ui_data(
-            render_frame()->GetRenderView()->ElementBoundsInWindow(
+            render_frame()->ElementBoundsInWindow(
                 current_generation_item_->generation_element_),
             current_generation_item_->generation_element_.MaxLength(),
             current_generation_item_->generation_element_.NameForAutofill()
@@ -513,7 +513,7 @@
   LogMessage(Logger::STRING_GENERATION_RENDERER_AUTOMATIC_GENERATION_AVAILABLE);
   autofill::password_generation::PasswordGenerationUIData
       password_generation_ui_data(
-          render_frame()->GetRenderView()->ElementBoundsInWindow(
+          render_frame()->ElementBoundsInWindow(
               current_generation_item_->generation_element_),
           current_generation_item_->generation_element_.MaxLength(),
           current_generation_item_->generation_element_.NameForAutofill()
@@ -532,9 +532,8 @@
   if (!render_frame())
     return;
 
-  gfx::RectF bounding_box =
-      render_frame()->GetRenderView()->ElementBoundsInWindow(
-          current_generation_item_->generation_element_);
+  gfx::RectF bounding_box = render_frame()->ElementBoundsInWindow(
+      current_generation_item_->generation_element_);
 
   std::unique_ptr<PasswordForm> password_form = CreatePasswordFormToPresave();
   DCHECK(password_form);
diff --git a/components/autofill/core/browser/autofill_merge_unittest.cc b/components/autofill/core/browser/autofill_merge_unittest.cc
index 1e101b1..b3d5aff 100644
--- a/components/autofill/core/browser/autofill_merge_unittest.cc
+++ b/components/autofill/core/browser/autofill_merge_unittest.cc
@@ -20,6 +20,7 @@
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/data_driven_test.h"
+#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h"
 #include "components/autofill/core/browser/form_data_importer.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/geo/country_names.h"
@@ -139,8 +140,8 @@
 std::string PersonalDataManagerMock::SaveImportedProfile(
     const AutofillProfile& profile) {
   std::vector<AutofillProfile> profiles;
-  std::string merged_guid =
-      MergeProfile(profile, &profiles_, "en-US", &profiles);
+  std::string merged_guid = AutofillProfileComparator::MergeProfile(
+      profile, &profiles_, "en-US", &profiles);
   if (merged_guid == profile.guid())
     profiles_.push_back(std::make_unique<AutofillProfile>(profile));
   return merged_guid;
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc
index e2ad2699..ff6b12a 100644
--- a/components/autofill/core/browser/autofill_metrics.cc
+++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -922,6 +922,11 @@
 }
 
 // static
+void AutofillMetrics::LogCardUnmaskPreflightCalled() {
+  UMA_HISTOGRAM_BOOLEAN("Autofill.BetterAuth.CardUnmaskPreflightCalled", true);
+}
+
+// static
 void AutofillMetrics::LogUnmaskPromptEvent(UnmaskPromptEvent event) {
   UMA_HISTOGRAM_ENUMERATION("Autofill.UnmaskPrompt.Events", event,
                             NUM_UNMASK_PROMPT_EVENTS);
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h
index 912f94b..4cac565 100644
--- a/components/autofill/core/browser/autofill_metrics.h
+++ b/components/autofill/core/browser/autofill_metrics.h
@@ -1033,6 +1033,10 @@
   static void LogUserHappinessByProfileFormType(UserHappinessMetric metric,
                                                 uint32_t profile_form_bitmask);
 
+  // Logs the count of calls to PaymentsClient::GetUnmaskDetails() (aka
+  // GetDetailsForGetRealPan).
+  static void LogCardUnmaskPreflightCalled();
+
   // Logs |event| to the unmask prompt events histogram.
   static void LogUnmaskPromptEvent(UnmaskPromptEvent event);
 
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc
index 29b5df9..6048384e 100644
--- a/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/autofill_external_delegate.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
@@ -28,6 +29,7 @@
 #include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h"
 #include "components/autofill/core/browser/metrics/form_events.h"
 #include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
+#include "components/autofill/core/browser/payments/credit_card_access_manager.h"
 #include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
 #include "components/autofill/core/browser/payments/test_payments_client.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
@@ -43,6 +45,7 @@
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_clock.h"
 #include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/prefs/pref_service.h"
@@ -57,6 +60,10 @@
 #include "ui/gfx/geometry/rect.h"
 #include "url/gurl.h"
 
+#if !defined(OS_IOS)
+#include "components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h"
+#endif
+
 using base::ASCIIToUTF16;
 using base::Bucket;
 using base::TimeTicks;
@@ -268,6 +275,10 @@
                            bool include_masked_server_credit_card,
                            bool include_full_server_credit_card);
 
+  // If set to true, then user is capable of using FIDO authentication for card
+  // unmasking.
+  void SetFidoEligibility(bool is_verifiable);
+
   // Mocks a RPC response from payments.
   void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
                        const std::string& real_pan);
@@ -343,6 +354,13 @@
       autofill_manager_.get(), autofill_driver_.get());
   autofill_manager_->SetExternalDelegate(external_delegate_.get());
 
+#if !defined(OS_IOS)
+  autofill_manager_->credit_card_access_manager()
+      ->set_fido_authenticator_for_testing(
+          std::make_unique<TestCreditCardFIDOAuthenticator>(
+              autofill_driver_.get(), &autofill_client_));
+#endif
+
   // Initialize the TestPersonalDataManager with some default data.
   CreateTestAutofillProfiles();
 }
@@ -392,6 +410,19 @@
   personal_data_->Refresh();
 }
 
+void AutofillMetricsTest::SetFidoEligibility(bool is_verifiable) {
+#if !defined(OS_IOS)
+  static_cast<TestCreditCardFIDOAuthenticator*>(
+      autofill_manager_->credit_card_access_manager()
+          ->GetOrCreateFIDOAuthenticator())
+      ->SetUserVerifiable(is_verifiable);
+#endif
+  autofill_manager_->credit_card_access_manager()
+      ->can_fetch_unmask_details_.Signal();
+  autofill_manager_->credit_card_access_manager()->is_user_verifiable_ =
+      base::nullopt;
+}
+
 void AutofillMetricsTest::OnDidGetRealPan(
     AutofillClient::PaymentsRpcResult result,
     const std::string& real_pan) {
@@ -4252,6 +4283,105 @@
   }
 }
 
+// Test that we log preflight calls for credit card unmasking.
+TEST_F(AutofillMetricsTest, CreditCardUnmaskingPreflightCall) {
+  scoped_feature_list_.InitAndEnableFeature(
+      features::kAutofillCreditCardAuthentication);
+  std::string preflight_call_metric =
+      "Autofill.BetterAuth.CardUnmaskPreflightCalled";
+
+  // Set up our form data.
+  FormData form;
+  FormFieldData field;
+  std::vector<ServerFieldType> field_types;
+  test::CreateTestFormField("Credit card", "card", "", "text", &field);
+  form.fields.push_back(field);
+  field_types.push_back(CREDIT_CARD_NUMBER);
+
+  // Simulate having seen this form on page load.
+  // |form_structure| will be owned by |autofill_manager_|.
+  autofill_manager_->AddSeenForm(form, field_types, field_types);
+
+  {
+    // Create local cards and set user as eligible for FIDO authentication.
+    base::HistogramTester histogram_tester;
+    RecreateCreditCards(true /* include_local_credit_card */,
+                        false /* include_masked_server_credit_card */,
+                        false /* include_full_server_credit_card */);
+    SetFidoEligibility(true);
+    autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form,
+                                          form.fields[0]);
+    // If no masked server cards are available, then no preflight call is made.
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
+  }
+
+  {
+    // Create masked server cards and set user as ineligible for FIDO
+    // authentication.
+    base::HistogramTester histogram_tester;
+    RecreateCreditCards(false /* include_local_credit_card */,
+                        true /* include_masked_server_credit_card */,
+                        false /* include_full_server_credit_card */);
+    SetFidoEligibility(false);
+    autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form,
+                                          form.fields[0]);
+    // If user is not verifiable, then no preflight call is made.
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
+  }
+
+  {
+    // Create full server cards and set user as eligible for FIDO
+    // authentication.
+    base::HistogramTester histogram_tester;
+    RecreateCreditCards(false /* include_local_credit_card */,
+                        false /* include_masked_server_credit_card */,
+                        true /* include_full_server_credit_card */);
+    SetFidoEligibility(false);
+    autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form,
+                                          form.fields[0]);
+    // If no masked server cards are available, then no preflight call is made.
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
+  }
+
+  {
+    // Create masked server cards and set user as eligible for FIDO
+    // authentication.
+    base::HistogramTester histogram_tester;
+    RecreateCreditCards(false /* include_local_credit_card */,
+                        true /* include_masked_server_credit_card */,
+                        false /* include_full_server_credit_card */);
+    SetFidoEligibility(true);
+    autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form,
+                                          form.fields[0]);
+    // Preflight call is made only if a masked server card is available and the
+    // user is eligible for FIDO authentication (except iOS).
+#if defined(OS_IOS)
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
+#else
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 1);
+#endif
+  }
+
+  {
+    // Create all types of cards and set user as eligible for FIDO
+    // authentication.
+    base::HistogramTester histogram_tester;
+    RecreateCreditCards(true /* include_local_credit_card */,
+                        true /* include_masked_server_credit_card */,
+                        true /* include_full_server_credit_card */);
+    SetFidoEligibility(true);
+    autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form,
+                                          form.fields[0]);
+    // Preflight call is made only if a masked server card is available and the
+    // user is eligible for FIDO authentication (except iOS).
+#if defined(OS_IOS)
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
+#else
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 1);
+#endif
+  }
+}
+
 // Test that we log submitted form events for credit cards.
 TEST_F(AutofillMetricsTest, CreditCardGetRealPanDuration) {
   // Creating masked card
diff --git a/components/autofill/core/browser/data_model/autofill_profile_comparator.cc b/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
index 9b41b0b..ac578d3 100644
--- a/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
+++ b/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
@@ -16,8 +16,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/address_rewriter.h"
 #include "components/autofill/core/browser/autofill_data_util.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/geo/autofill_country.h"
 #include "components/autofill/core/browser/geo/state_names.h"
+#include "components/autofill/core/common/autofill_clock.h"
 #include "third_party/libphonenumber/phonenumber_api.h"
 
 using base::UTF16ToUTF8;
@@ -829,6 +831,70 @@
 }
 
 // static
+std::string AutofillProfileComparator::MergeProfile(
+    const AutofillProfile& new_profile,
+    std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles,
+    const std::string& app_locale,
+    std::vector<AutofillProfile>* merged_profiles) {
+  merged_profiles->clear();
+
+  // Sort the existing profiles in decreasing order of frecency, so the "best"
+  // profiles are checked first. Put the verified profiles last so the non
+  // verified profiles get deduped among themselves before reaching the verified
+  // profiles.
+  // TODO(crbug.com/620521): Remove the check for verified from the sort.
+  base::Time comparison_time = AutofillClock::Now();
+  std::sort(existing_profiles->begin(), existing_profiles->end(),
+            [comparison_time](const std::unique_ptr<AutofillProfile>& a,
+                              const std::unique_ptr<AutofillProfile>& b) {
+              if (a->IsVerified() != b->IsVerified())
+                return !a->IsVerified();
+              return a->HasGreaterFrecencyThan(b.get(), comparison_time);
+            });
+
+  // Set to true if |existing_profiles| already contains an equivalent profile.
+  bool matching_profile_found = false;
+  std::string guid = new_profile.guid();
+
+  // If we have already saved this address, merge in any missing values.
+  // Only merge with the first match. Merging the new profile into the existing
+  // one preserves the validity of credit card's billing address reference.
+  AutofillProfileComparator comparator(app_locale);
+  for (const auto& existing_profile : *existing_profiles) {
+    if (!matching_profile_found &&
+        comparator.AreMergeable(new_profile, *existing_profile) &&
+        existing_profile->SaveAdditionalInfo(new_profile, app_locale)) {
+      // Unverified profiles should always be updated with the newer data,
+      // whereas verified profiles should only ever be overwritten by verified
+      // data.  If an automatically aggregated profile would overwrite a
+      // verified profile, just drop it.
+      matching_profile_found = true;
+      guid = existing_profile->guid();
+
+      // We set the modification date so that immediate requests for profiles
+      // will properly reflect the fact that this profile has been modified
+      // recently. After writing to the database and refreshing the local copies
+      // the profile will have a very slightly newer time reflecting what's
+      // actually stored in the database.
+      existing_profile->set_modification_date(AutofillClock::Now());
+    }
+    merged_profiles->push_back(*existing_profile);
+  }
+
+  // If the new profile was not merged with an existing one, add it to the list.
+  if (!matching_profile_found) {
+    merged_profiles->push_back(new_profile);
+    // Similar to updating merged profiles above, set the modification date on
+    // new profiles.
+    merged_profiles->back().set_modification_date(AutofillClock::Now());
+    AutofillMetrics::LogProfileActionOnFormSubmitted(
+        AutofillMetrics::NEW_PROFILE_CREATED);
+  }
+
+  return guid;
+}
+
+// static
 std::set<base::StringPiece16> AutofillProfileComparator::UniqueTokens(
     base::StringPiece16 s) {
   std::vector<base::StringPiece16> tokens = base::SplitStringPiece(
diff --git a/components/autofill/core/browser/data_model/autofill_profile_comparator.h b/components/autofill/core/browser/data_model/autofill_profile_comparator.h
index 127c8287..525bf07 100644
--- a/components/autofill/core/browser/data_model/autofill_profile_comparator.h
+++ b/components/autofill/core/browser/data_model/autofill_profile_comparator.h
@@ -138,6 +138,16 @@
   // App locale used when this comparator instance was created.
   const std::string app_locale() const { return app_locale_; }
 
+  // Merges |new_profile| into one of the |existing_profiles| if possible;
+  // otherwise appends |new_profile| to the end of that list. Fills
+  // |merged_profiles| with the result. Returns the |guid| of the new or updated
+  // profile.
+  static std::string MergeProfile(
+      const AutofillProfile& new_profile,
+      std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles,
+      const std::string& app_locale,
+      std::vector<AutofillProfile>* merged_profiles);
+
  protected:
   // The result type returned by CompareTokens.
   enum CompareTokensResult {
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc
index a7c34fd4..cd7d3d8 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager.cc
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -209,12 +209,14 @@
   // If user is verifiable, then make preflight call to payments to fetch unmask
   // details, otherwise the only option is to perform CVC Auth, which does not
   // require any. Do nothing if request is already in progress.
-  if (is_user_verifiable_ && !unmask_details_request_in_progress_) {
+  if (is_user_verifiable_.value_or(false) &&
+      !unmask_details_request_in_progress_) {
     unmask_details_request_in_progress_ = true;
     payments_client_->GetUnmaskDetails(
         base::BindOnce(&CreditCardAccessManager::OnDidGetUnmaskDetails,
                        weak_ptr_factory_.GetWeakPtr()),
         personal_data_manager_->app_locale());
+    AutofillMetrics::LogCardUnmaskPreflightCalled();
   }
 }
 
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
index 63c6f9c7..3903e7a 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -191,6 +191,11 @@
     return credit_card_access_manager_->is_authentication_in_progress();
   }
 
+  void ResetPreflightCallLimiter() {
+    credit_card_access_manager_->can_fetch_unmask_details_.Signal();
+    credit_card_access_manager_->is_user_verifiable_ = base::nullopt;
+  }
+
   void CreateLocalCard(std::string guid, std::string number = std::string()) {
     CreditCard local_card = CreditCard();
     test::SetCreditCardInfo(&local_card, "Elvis Presley", number.c_str(),
@@ -507,6 +512,68 @@
   EXPECT_EQ(ASCIIToUTF16(kTestNumber), accessor_->number());
 }
 
+// Ensures that CardUnmaskPreflightCalled metrics are logged correctly.
+TEST_F(CreditCardAccessManagerTest, CardUnmaskPreflightCalledMetric) {
+  std::string preflight_call_metric =
+      "Autofill.BetterAuth.CardUnmaskPreflightCalled";
+
+  {
+    // Create local card and set user as eligible for FIDO auth.
+    base::HistogramTester histogram_tester;
+    CreateLocalCard(kTestGUID, kTestNumber);
+#if !defined(OS_IOS)
+    GetFIDOAuthenticator()->SetUserVerifiable(true);
+#endif
+    ResetPreflightCallLimiter();
+
+    credit_card_access_manager_->PrepareToFetchCreditCard();
+    InvokeUnmaskDetailsTimeout();
+    WaitForCallbacks();
+
+    // If only local cards are available, then no preflight call is made.
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
+  }
+
+  {
+    // Create server card and set user as ineligible for FIDO auth.
+    base::HistogramTester histogram_tester;
+    CreateServerCard(kTestGUID, kTestNumber);
+#if !defined(OS_IOS)
+    GetFIDOAuthenticator()->SetUserVerifiable(false);
+#endif
+    ResetPreflightCallLimiter();
+
+    credit_card_access_manager_->PrepareToFetchCreditCard();
+    InvokeUnmaskDetailsTimeout();
+    WaitForCallbacks();
+
+    // If user is not verifiable, then no preflight call is made.
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
+  }
+
+  {
+    // Create server card and set user as eligible for FIDO auth.
+    base::HistogramTester histogram_tester;
+    CreateServerCard(kTestGUID, kTestNumber);
+#if !defined(OS_IOS)
+    GetFIDOAuthenticator()->SetUserVerifiable(true);
+#endif
+    ResetPreflightCallLimiter();
+
+    credit_card_access_manager_->PrepareToFetchCreditCard();
+    InvokeUnmaskDetailsTimeout();
+    WaitForCallbacks();
+
+    // Preflight call is made only if a server card is available and the user is
+    // eligible for FIDO authentication, except on iOS.
+#if defined(OS_IOS)
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
+#else
+    histogram_tester.ExpectTotalCount(preflight_call_metric, 1);
+#endif
+  }
+}
+
 #if !defined(OS_IOS)
 // Ensures that FetchCreditCard() returns the full PAN upon a successful
 // WebAuthn verification and response from payments.
diff --git a/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc b/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
index 86c632c9..ea5efc5 100644
--- a/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
+++ b/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
@@ -127,8 +127,10 @@
     base::OnceCallback<void(bool)> callback) {
   if (base::FeatureList::IsEnabled(
           features::kAutofillCreditCardAuthentication)) {
-    autofill_driver_->ConnectToAuthenticator(
-        authenticator_.BindNewPipeAndPassReceiver());
+    if (!authenticator_.is_bound()) {
+      autofill_driver_->ConnectToAuthenticator(
+          authenticator_.BindNewPipeAndPassReceiver());
+    }
     authenticator_->IsUserVerifyingPlatformAuthenticatorAvailable(
         std::move(callback));
   } else {
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 49de5f4..1a24880 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -1430,70 +1430,6 @@
   return empty_validity_map;
 }
 
-// static
-std::string PersonalDataManager::MergeProfile(
-    const AutofillProfile& new_profile,
-    std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles,
-    const std::string& app_locale,
-    std::vector<AutofillProfile>* merged_profiles) {
-  merged_profiles->clear();
-
-  // Sort the existing profiles in decreasing order of frecency, so the "best"
-  // profiles are checked first. Put the verified profiles last so the non
-  // verified profiles get deduped among themselves before reaching the verified
-  // profiles.
-  // TODO(crbug.com/620521): Remove the check for verified from the sort.
-  base::Time comparison_time = AutofillClock::Now();
-  std::sort(existing_profiles->begin(), existing_profiles->end(),
-            [comparison_time](const std::unique_ptr<AutofillProfile>& a,
-                              const std::unique_ptr<AutofillProfile>& b) {
-              if (a->IsVerified() != b->IsVerified())
-                return !a->IsVerified();
-              return a->HasGreaterFrecencyThan(b.get(), comparison_time);
-            });
-
-  // Set to true if |existing_profiles| already contains an equivalent profile.
-  bool matching_profile_found = false;
-  std::string guid = new_profile.guid();
-
-  // If we have already saved this address, merge in any missing values.
-  // Only merge with the first match. Merging the new profile into the existing
-  // one preserves the validity of credit card's billing address reference.
-  AutofillProfileComparator comparator(app_locale);
-  for (const auto& existing_profile : *existing_profiles) {
-    if (!matching_profile_found &&
-        comparator.AreMergeable(new_profile, *existing_profile) &&
-        existing_profile->SaveAdditionalInfo(new_profile, app_locale)) {
-      // Unverified profiles should always be updated with the newer data,
-      // whereas verified profiles should only ever be overwritten by verified
-      // data.  If an automatically aggregated profile would overwrite a
-      // verified profile, just drop it.
-      matching_profile_found = true;
-      guid = existing_profile->guid();
-
-      // We set the modification date so that immediate requests for profiles
-      // will properly reflect the fact that this profile has been modified
-      // recently. After writing to the database and refreshing the local copies
-      // the profile will have a very slightly newer time reflecting what's
-      // actually stored in the database.
-      existing_profile->set_modification_date(AutofillClock::Now());
-    }
-    merged_profiles->push_back(*existing_profile);
-  }
-
-  // If the new profile was not merged with an existing one, add it to the list.
-  if (!matching_profile_found) {
-    merged_profiles->push_back(new_profile);
-    // Similar to updating merged profiles above, set the modification date on
-    // new profiles.
-    merged_profiles->back().set_modification_date(AutofillClock::Now());
-    AutofillMetrics::LogProfileActionOnFormSubmitted(
-        AutofillMetrics::NEW_PROFILE_CREATED);
-  }
-
-  return guid;
-}
-
 const std::string& PersonalDataManager::GetDefaultCountryCodeForNewAddress()
     const {
   if (default_country_code_.empty())
@@ -1716,8 +1652,8 @@
     return std::string();
 
   std::vector<AutofillProfile> profiles;
-  std::string guid =
-      MergeProfile(imported_profile, &web_profiles_, app_locale_, &profiles);
+  std::string guid = AutofillProfileComparator::MergeProfile(
+      imported_profile, &web_profiles_, app_locale_, &profiles);
   SetProfiles(&profiles);
   return guid;
 }
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 0a83a6f..bacee0a 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -323,16 +323,6 @@
 
   const std::string& app_locale() const { return app_locale_; }
 
-  // Merges |new_profile| into one of the |existing_profiles| if possible;
-  // otherwise appends |new_profile| to the end of that list. Fills
-  // |merged_profiles| with the result. Returns the |guid| of the new or updated
-  // profile.
-  static std::string MergeProfile(
-      const AutofillProfile& new_profile,
-      std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles,
-      const std::string& app_locale,
-      std::vector<AutofillProfile>* merged_profiles);
-
   // Returns our best guess for the country a user is likely to use when
   // inputting a new address. The value is calculated once and cached, so it
   // will only update when Chrome is restarted.
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index 78caa79..2729e29 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -4467,7 +4467,7 @@
 
   // Merge the imported profile into the existing profiles.
   std::vector<AutofillProfile> profiles;
-  std::string guid = personal_data_->MergeProfile(
+  std::string guid = AutofillProfileComparator::MergeProfile(
       imported_profile, &existing_profiles, "US-EN", &profiles);
 
   // The new profile should be merged into the "fox" profile.
@@ -4516,7 +4516,7 @@
 
   // Merge the imported profile into the existing profiles.
   std::vector<AutofillProfile> profiles;
-  std::string guid = personal_data_->MergeProfile(
+  std::string guid = AutofillProfileComparator::MergeProfile(
       imported_profile, &existing_profiles, "US-EN", &profiles);
 
   // The new profile should be merged into the existing profile.
diff --git a/components/content_settings/core/browser/website_settings_registry.cc b/components/content_settings/core/browser/website_settings_registry.cc
index 62d824a..e7627f3 100644
--- a/components/content_settings/core/browser/website_settings_registry.cc
+++ b/components/content_settings/core/browser/website_settings_registry.cc
@@ -157,11 +157,11 @@
            WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
            DESKTOP | PLATFORM_ANDROID,
            WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
-  Register(CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, "password-protection",
-           nullptr, WebsiteSettingsInfo::UNSYNCABLE,
-           WebsiteSettingsInfo::NOT_LOSSY,
-           WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
-           DESKTOP, WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
+  Register(
+      CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, "password-protection", nullptr,
+      WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
+      WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
+      DESKTOP | PLATFORM_ANDROID, WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
   // Set when an origin is activated for subresource filtering and the
   // associated UI is shown to the user. Cleared when a site is de-activated or
   // the first URL matching the origin is removed from history.
diff --git a/components/crash/content/app/crashpad_linux.cc b/components/crash/content/app/crashpad_linux.cc
index 56908c48..dd27c7742 100644
--- a/components/crash/content/app/crashpad_linux.cc
+++ b/components/crash/content/app/crashpad_linux.cc
@@ -23,6 +23,32 @@
 
 namespace crash_reporter {
 
+namespace {
+
+// TODO(jperaza): This is the first chance handler type used by Breakpad and v8.
+// The Crashpad FirstChanceHandler type explicitly declares the third parameter
+// to be a ucontext_t* instead of a void*. Using a reinterpret cast to convert
+// one function type to another causes calling the handler to fail with SIGILL
+// when CFI is enabled. Use a helper with Crashpad's FirstChanceHandler type
+// to delegate to the real first chance handler instead of re-interpreting the
+// handler itself. This can be removed if the two function types converge.
+bool (*g_first_chance_handler)(int, siginfo_t*, void*);
+
+bool FirstChanceHandlerHelper(int signo,
+                              siginfo_t* siginfo,
+                              ucontext_t* context) {
+  return g_first_chance_handler(signo, siginfo, context);
+}
+
+}  // namespace
+
+void SetFirstChanceExceptionHandler(bool (*handler)(int, siginfo_t*, void*)) {
+  DCHECK(!g_first_chance_handler);
+  g_first_chance_handler = handler;
+  crashpad::CrashpadClient::SetFirstChanceExceptionHandler(
+      FirstChanceHandlerHelper);
+}
+
 // TODO(jperaza): Remove kEnableCrashpad and IsCrashpadEnabled() when Crashpad
 // is fully enabled on Linux.
 const char kEnableCrashpad[] = "enable-crashpad";
@@ -31,11 +57,6 @@
   return base::CommandLine::ForCurrentProcess()->HasSwitch(kEnableCrashpad);
 }
 
-void SetFirstChanceExceptionHandler(bool (*handler)(int, siginfo_t*, void*)) {
-  crashpad::CrashpadClient::SetFirstChanceExceptionHandler(
-      reinterpret_cast<crashpad::CrashpadClient::FirstChanceHandler>(handler));
-}
-
 bool GetHandlerSocket(int* fd, pid_t* pid) {
   return crashpad::CrashpadClient::GetHandlerSocket(fd, pid);
 }
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 915b6f9..6206d3f 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -1118,14 +1118,13 @@
 }
 
 bool AutocompleteMatch::ShouldShowTabMatchButton() const {
+  // TODO(pkasting): This kind of presentational logic does not belong on
+  // AutocompleteMatch and should be e.g. a static method in
+  // OmniboxMatchCellView that takes an AutocompleteMatch.
   return has_tab_match && !associated_keyword &&
          !OmniboxFieldTrial::IsTabSwitchSuggestionsDedicatedRowEnabled();
 }
 
-bool AutocompleteMatch::ShouldShowButton() const {
-  return ShouldShowTabMatchButton();
-}
-
 bool AutocompleteMatch::IsTabSwitchSuggestion() const {
   return (subrelevance & ~FAMILY_SIZE_MASK) == TAB_SWITCH_FAMILY_ID;
 }
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index a756136..3fa30a6 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -446,9 +446,6 @@
   // is taking precedence.
   bool ShouldShowTabMatchButton() const;
 
-  // Returns true if the suggestion should show a tab match button or pedal.
-  bool ShouldShowButton() const;
-
   // Returns whether the suggestion is by itself a tab switch suggestion.
   bool IsTabSwitchSuggestion() const;
 
diff --git a/components/omnibox/browser/omnibox_controller.cc b/components/omnibox/browser/omnibox_controller.cc
index 1f86516f..d8ea555 100644
--- a/components/omnibox/browser/omnibox_controller.cc
+++ b/components/omnibox/browser/omnibox_controller.cc
@@ -35,7 +35,7 @@
 
   if (client_->GetOmniboxControllerEmitter()) {
     client_->GetOmniboxControllerEmitter()->NotifyOmniboxQuery(
-        autocomplete_controller_.get(), input.text());
+        autocomplete_controller_.get(), input);
   }
 
   // We don't explicitly clear OmniboxPopupModel::manually_selected_match, as
diff --git a/components/omnibox/browser/omnibox_controller_emitter.cc b/components/omnibox/browser/omnibox_controller_emitter.cc
index 0e17327..a8f36203 100644
--- a/components/omnibox/browser/omnibox_controller_emitter.cc
+++ b/components/omnibox/browser/omnibox_controller_emitter.cc
@@ -69,9 +69,9 @@
 
 void OmniboxControllerEmitter::NotifyOmniboxQuery(
     AutocompleteController* controller,
-    const base::string16& input_text) {
+    const AutocompleteInput& input) {
   for (Observer& observer : observers_)
-    observer.OnOmniboxQuery(controller, input_text);
+    observer.OnOmniboxQuery(controller, input);
 }
 
 void OmniboxControllerEmitter::NotifyOmniboxResultChanged(
diff --git a/components/omnibox/browser/omnibox_controller_emitter.h b/components/omnibox/browser/omnibox_controller_emitter.h
index ce27cb5..2a7a99a 100644
--- a/components/omnibox/browser/omnibox_controller_emitter.h
+++ b/components/omnibox/browser/omnibox_controller_emitter.h
@@ -23,7 +23,7 @@
     // Invoked when new autocomplete queries are made from the omnibox
     // controller or when those queries' results change.
     virtual void OnOmniboxQuery(AutocompleteController* controller,
-                                const base::string16& input_text) = 0;
+                                const AutocompleteInput& input) = 0;
     virtual void OnOmniboxResultChanged(bool default_match_changed,
                                         AutocompleteController* controller) = 0;
   };
@@ -43,7 +43,7 @@
   // Notifies registered observers when new autocomplete queries are made from
   // the omnibox controller or when those queries' results change.
   void NotifyOmniboxQuery(AutocompleteController* controller,
-                          const base::string16& input_text);
+                          const AutocompleteInput& input);
   void NotifyOmniboxResultChanged(bool default_match_changed,
                                   AutocompleteController* controller);
 
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc
index 0ca252c..476e38f7 100644
--- a/components/omnibox/browser/omnibox_popup_model.cc
+++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -334,11 +334,6 @@
          result().match_at(selected_line_).ShouldShowTabMatchButton();
 }
 
-bool OmniboxPopupModel::SelectedLineHasButton() {
-  return selected_line_ != kNoMatch &&
-         result().match_at(selected_line_).ShouldShowButton();
-}
-
 bool OmniboxPopupModel::SelectedLineIsTabSwitchSuggestion() {
   return selected_line_ != kNoMatch &&
          result().match_at(selected_line_).IsTabSwitchSuggestion();
diff --git a/components/omnibox/browser/omnibox_popup_model.h b/components/omnibox/browser/omnibox_popup_model.h
index f66d803f..8f8d1e6 100644
--- a/components/omnibox/browser/omnibox_popup_model.h
+++ b/components/omnibox/browser/omnibox_popup_model.h
@@ -146,10 +146,6 @@
   // tab switch button.
   bool SelectedLineHasTabMatch();
 
-  // Helper function to see if current selection has button and can accept
-  // the tab key.
-  bool SelectedLineHasButton();
-
   // Helper function to see if current selection is a tab switch suggestion
   // dedicated row.
   bool SelectedLineIsTabSwitchSuggestion();
diff --git a/components/optimization_guide/hints_fetcher.cc b/components/optimization_guide/hints_fetcher.cc
index d8dd5e68..a9b80126 100644
--- a/components/optimization_guide/hints_fetcher.cc
+++ b/components/optimization_guide/hints_fetcher.cc
@@ -103,8 +103,11 @@
   if (url_loader_)
     return false;
 
-  hints_fetch_start_time_ = base::TimeTicks::Now();
+  std::vector<std::string> filtered_hosts = GetHostsDueForHintsRefresh(hosts);
+  if (filtered_hosts.empty())
+    return false;
 
+  hints_fetch_start_time_ = base::TimeTicks::Now();
   request_context_ = request_context;
 
   get_hints_request_ = std::make_unique<proto::GetHintsRequest>();
@@ -120,7 +123,7 @@
 
   get_hints_request_->set_context(request_context_);
 
-  for (const auto& host : hosts) {
+  for (const auto& host : filtered_hosts) {
     proto::HostInfo* host_info = get_hints_request_->add_hosts();
     host_info->set_host(host);
   }
@@ -165,7 +168,8 @@
                                      "application/x-protobuf");
 
   UMA_HISTOGRAM_COUNTS_100(
-      "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", hosts.size());
+      "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount",
+      filtered_hosts.size());
 
   // |url_loader_| should not retry on 5xx errors since the server may already
   // be overloaded.  |url_loader_| should retry on network changes since the
@@ -179,7 +183,7 @@
       base::BindOnce(&HintsFetcher::OnURLLoadComplete, base::Unretained(this)));
 
   hints_fetched_callback_ = std::move(hints_fetched_callback);
-  hosts_fetched_ = hosts;
+  hosts_fetched_ = filtered_hosts;
   return true;
 }
 
@@ -279,4 +283,32 @@
   url_loader_.reset();
 }
 
+std::vector<std::string> HintsFetcher::GetHostsDueForHintsRefresh(
+    const std::vector<std::string>& hosts) const {
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  DictionaryPrefUpdate hosts_fetched(
+      pref_service_, prefs::kHintsFetcherHostsSuccessfullyFetched);
+
+  std::vector<std::string> target_hosts;
+  target_hosts.reserve(hosts.size());
+
+  for (const auto& host : hosts) {
+    bool host_hints_due_for_refresh = true;
+
+    base::Optional<double> value =
+        hosts_fetched->FindDoubleKey(HashHostForDictionary(host));
+    if (value) {
+      base::Time host_valid_time = base::Time::FromDeltaSinceWindowsEpoch(
+          base::TimeDelta::FromSecondsD(*value));
+      host_hints_due_for_refresh =
+          (host_valid_time - features::GetHintsFetchRefreshDuration() <=
+           time_clock_->Now());
+    }
+    if (host_hints_due_for_refresh)
+      target_hosts.push_back(host);
+  }
+  return target_hosts;
+}
+
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/hints_fetcher.h b/components/optimization_guide/hints_fetcher.h
index f9a6720..6ee86c5 100644
--- a/components/optimization_guide/hints_fetcher.h
+++ b/components/optimization_guide/hints_fetcher.h
@@ -95,6 +95,11 @@
   // in the pref.
   void UpdateHostsSuccessfullyFetched();
 
+  // Returns the subset of hosts from |hosts| for which the hints should be
+  // refreshed.
+  std::vector<std::string> GetHostsDueForHintsRefresh(
+      const std::vector<std::string>& hosts) const;
+
   // Used to hold the GetHintsRequest being constructed and sent as a remote
   // request.
   std::unique_ptr<proto::GetHintsRequest> get_hints_request_;
diff --git a/components/optimization_guide/hints_fetcher_unittest.cc b/components/optimization_guide/hints_fetcher_unittest.cc
index 2c0b70b2..ad13417 100644
--- a/components/optimization_guide/hints_fetcher_unittest.cc
+++ b/components/optimization_guide/hints_fetcher_unittest.cc
@@ -96,6 +96,10 @@
     return task_environment_.GetMockClock();
   }
 
+  void SetTimeClockForTesting(base::Clock* clock) {
+    hints_fetcher_->SetTimeClockForTesting(clock);
+  }
+
  protected:
   bool FetchHints(const std::vector<std::string>& hosts) {
     bool status = hints_fetcher_->FetchOptimizationGuideServiceHints(
@@ -153,7 +157,7 @@
   base::HistogramTester histogram_tester;
 
   std::string response_content;
-  EXPECT_TRUE(FetchHints(std::vector<std::string>()));
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"foo.com"}));
   VerifyHasPendingFetchRequests();
   EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK));
   EXPECT_TRUE(hints_fetched());
@@ -164,16 +168,73 @@
 
 // Tests to ensure that multiple hint fetches by the same object cannot be in
 // progress simultaneously.
-TEST_F(HintsFetcherTest, FetchInProcess) {
+TEST_F(HintsFetcherTest, FetchInProgress) {
+  base::SimpleTestClock test_clock;
+  SetTimeClockForTesting(&test_clock);
+
   std::string response_content;
   // Fetch back to back without waiting for Fetch to complete,
   // |fetch_in_progress_| should cause early exit.
-  EXPECT_TRUE(FetchHints(std::vector<std::string>()));
-  EXPECT_FALSE(FetchHints(std::vector<std::string>()));
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"foo.com"}));
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"bar.com"}));
 
   // Once response arrives, check to make sure a new fetch can start.
   SimulateResponse(response_content, net::HTTP_OK);
-  EXPECT_TRUE(FetchHints(std::vector<std::string>()));
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"bar.com"}));
+}
+
+// Tests that the hints are refreshed again for hosts for whom hints were
+// fetched recently.
+TEST_F(HintsFetcherTest, FetchInProgress_HostsHintsRefreshed) {
+  base::SimpleTestClock test_clock;
+  SetTimeClockForTesting(&test_clock);
+
+  std::string response_content;
+  // Fetch back to back without waiting for Fetch to complete,
+  // |fetch_in_progress_| should cause early exit.
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"foo.com"}));
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"foo.com"}));
+
+  // Once response arrives, check to make sure that the fetch for the same host
+  // is not started again.
+  SimulateResponse(response_content, net::HTTP_OK);
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"foo.com"}));
+  // Ensure a new fetch for a different host can start.
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"bar.com"}));
+  SimulateResponse(response_content, net::HTTP_OK);
+
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"foo.com"}));
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"bar.com"}));
+
+  std::vector<std::string> hosts{"foo.com", "bar.com"};
+  // Advancing the clock so that it's still one hour before the hints need to be
+  // refreshed.
+  test_clock.Advance(features::StoredFetchedHintsFreshnessDuration() -
+                     features::GetHintsFetchRefreshDuration() -
+                     base::TimeDelta().FromHours(1));
+
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"foo.com"}));
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"bar.com"}));
+
+  // Advancing the clock by a little bit more than 1 hour so that the hints are
+  // now due for refresh.
+  test_clock.Advance(base::TimeDelta::FromMinutes(61));
+
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"foo.com"}));
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"bar.com"}));
+  SimulateResponse(response_content, net::HTTP_OK);
+
+  // Hints should not be fetched again for foo.com since they were fetched
+  // recently. Hints should still be fetched for bar.com.
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"foo.com"}));
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"bar.com"}));
+  SimulateResponse(response_content, net::HTTP_OK);
+
+  // Hints should not be fetched again for foo.com and bar.com since they were
+  // fetched recently. For baz.com, hints should be fetched again.
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"foo.com"}));
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"bar.com"}));
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"baz.com"}));
 }
 
 // Tests 404 response from request.
@@ -182,7 +243,7 @@
 
   std::string response_content;
 
-  EXPECT_TRUE(FetchHints(std::vector<std::string>()));
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"foo.com"}));
 
   // Send a 404 to HintsFetcher.
   SimulateResponse(response_content, net::HTTP_NOT_FOUND);
@@ -197,7 +258,7 @@
   base::HistogramTester histogram_tester;
 
   std::string response_content = "not proto";
-  EXPECT_TRUE(FetchHints(std::vector<std::string>()));
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"foo.com"}));
   VerifyHasPendingFetchRequests();
   EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK));
   EXPECT_FALSE(hints_fetched());
@@ -212,7 +273,7 @@
 
   SetConnectionOffline();
   std::string response_content;
-  EXPECT_FALSE(FetchHints(std::vector<std::string>()));
+  EXPECT_FALSE(FetchHints(std::vector<std::string>{"foo.com"}));
   EXPECT_FALSE(hints_fetched());
 
   // Make sure histogram not recorded on bad response.
@@ -220,7 +281,7 @@
       "OptimizationGuide.HintsFetcher.GetHintsRequest.FetchLatency", 0);
 
   SetConnectionOnline();
-  EXPECT_TRUE(FetchHints(std::vector<std::string>()));
+  EXPECT_TRUE(FetchHints(std::vector<std::string>{"foo.com"}));
   VerifyHasPendingFetchRequests();
   EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK));
   EXPECT_TRUE(hints_fetched());
diff --git a/components/optimization_guide/optimization_guide_decider.h b/components/optimization_guide/optimization_guide_decider.h
index 3852a1a..a38abba 100644
--- a/components/optimization_guide/optimization_guide_decider.h
+++ b/components/optimization_guide/optimization_guide_decider.h
@@ -39,10 +39,12 @@
 
 class OptimizationGuideDecider {
  public:
-  // Registers the optimization types that intend to be queried during the
-  // session.
-  virtual void RegisterOptimizationTypes(
-      std::vector<proto::OptimizationType> optimization_types) = 0;
+  // Registers the optimization types and targets that intend to be queried
+  // during the session. It is expected for this to be called after the browser
+  // has been initialized.
+  virtual void RegisterOptimizationTypesAndTargets(
+      const std::vector<proto::OptimizationType>& optimization_types,
+      const std::vector<proto::OptimizationTarget>& optimization_targets) = 0;
 
   // Returns whether the current conditions match |optimization_target| and
   // |optimization_type| can be applied for the URL associated with
diff --git a/components/optimization_guide/optimization_guide_features.cc b/components/optimization_guide/optimization_guide_features.cc
index 5254694..070879b 100644
--- a/components/optimization_guide/optimization_guide_features.cc
+++ b/components/optimization_guide/optimization_guide_features.cc
@@ -158,5 +158,9 @@
   return net::GetEffectiveConnectionTypeForName(param_value);
 }
 
+base::TimeDelta GetHintsFetchRefreshDuration() {
+  return base::TimeDelta::FromHours(72);
+}
+
 }  // namespace features
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/optimization_guide_features.h b/components/optimization_guide/optimization_guide_features.h
index 78b262108..a981499e 100644
--- a/components/optimization_guide/optimization_guide_features.h
+++ b/components/optimization_guide/optimization_guide_features.h
@@ -80,6 +80,12 @@
 base::Optional<net::EffectiveConnectionType>
 GetMaxEffectiveConnectionTypeForNavigationHintsFetch();
 
+// Returns the duration of the time window before hints expiration during which
+// the hosts should be refreshed. Example: If the hints for a host expire at
+// time T, then they are eligible for refresh at T -
+// GetHintsFetchRefreshDuration().
+base::TimeDelta GetHintsFetchRefreshDuration();
+
 }  // namespace features
 }  // namespace optimization_guide
 
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp
index a18c7a2d..c833f32 100644
--- a/components/page_info_strings.grdp
+++ b/components/page_info_strings.grdp
@@ -471,6 +471,9 @@
         <message name="IDS_PAGE_INFO_IGNORE_PASSWORD_WARNING_BUTTON" desc="In Title Case: The string used in the page info ignore password warning button.">
           Ignore
         </message>
+        <message name="IDS_PAGE_INFO_DISMISS_PASSWORD_WARNING_BUTTON" desc="In Title Case: The string used in the page info dismiss password warning button.">
+          Dismiss
+        </message>
       </if>
       <if expr="not use_titlecase">
         <message name="IDS_PAGE_INFO_CHANGE_PASSWORD_BUTTON" desc="The string used in the page info change password button.">
@@ -482,7 +485,10 @@
         <message name="IDS_PAGE_INFO_IGNORE_PASSWORD_WARNING_BUTTON" desc="The string used in the page info ignore password warning button.">
           Ignore
         </message>
-      </if>
+        <message name="IDS_PAGE_INFO_DISMISS_PASSWORD_WARNING_BUTTON" desc="The string used in the page info dismiss password warning button.">
+          Dismiss
+        </message>
+       </if>
       <message name="IDS_PAGE_INFO_WHITELIST_PASSWORD_REUSE_BUTTON" desc="The string used in the page info whitelist password reuse button.">
         Site is legitimate
       </message>
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
index 1541e71e..8a2af83 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -326,10 +326,7 @@
       base::TimeDelta::FromMilliseconds(40);
   subframe = content::NavigationSimulator::NavigateAndCommitFromDocument(
       GURL(kDefaultTestUrl2), subframe);
-  content::RenderFrameHostTester* subframe_tester =
-      content::RenderFrameHostTester::For(subframe);
   SimulateTimingUpdate(subframe_timing, subframe);
-  subframe_tester->SimulateNavigationStop();
 
   ASSERT_EQ(1, CountUpdatedSubFrameTimingReported());
   EXPECT_TRUE(subframe_timing.Equals(*updated_subframe_timings().back()));
@@ -821,10 +818,7 @@
   content::RenderFrameHost* subframe = rfh_tester->AppendChild("subframe");
   subframe = content::NavigationSimulator::NavigateAndCommitFromDocument(
       GURL(kDefaultTestUrl2), subframe);
-  content::RenderFrameHostTester* subframe_tester =
-      content::RenderFrameHostTester::For(subframe);
   SimulateTimingUpdateWithoutFiringDispatchTimer(subframe_timing, subframe);
-  subframe_tester->SimulateNavigationStop();
 
   histogram_tester_.ExpectTotalCount(
       page_load_metrics::internal::kHistogramOutOfOrderTiming, 1);
@@ -869,10 +863,7 @@
   content::RenderFrameHost* subframe2 = rfh_tester->AppendChild("subframe");
   subframe2 = content::NavigationSimulator::NavigateAndCommitFromDocument(
       GURL(kDefaultTestUrl2), subframe2);
-  content::RenderFrameHostTester* subframe2_tester =
-      content::RenderFrameHostTester::For(subframe2);
   SimulateTimingUpdateWithoutFiringDispatchTimer(subframe_timing, subframe2);
-  subframe2_tester->SimulateNavigationStop();
 
   base::TimeDelta updated_first_paint =
       updated_timings().back()->paint_timing->first_paint.value();
diff --git a/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc b/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
index bfe608e..9b9735eb 100644
--- a/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
+++ b/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
@@ -137,6 +137,8 @@
           WebFeature::kThirdPartySharedWorker,
           WebFeature::kThirdPartyBroadcastChannel,
           WebFeature::kHeavyAdIntervention,
+          WebFeature::kGetGamepadsFromCrossOriginSubframe,
+          WebFeature::kGetGamepadsFromInsecureContext,
       }));
   return *opt_in_features;
 }
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn
index 77b9fa2..bcfb174 100644
--- a/components/performance_manager/BUILD.gn
+++ b/components/performance_manager/BUILD.gn
@@ -74,9 +74,9 @@
   public_deps = [
     "//base",
     "//base/allocator:buildflags",
+    "//components/performance_manager/public/mojom",
     "//content/public/browser",
     "//services/metrics/public/cpp:metrics_cpp",
-    "//services/resource_coordinator/public/mojom",
     "//url",
   ]
 }
diff --git a/components/performance_manager/DEPS b/components/performance_manager/DEPS
index 2da3809..ef901062 100644
--- a/components/performance_manager/DEPS
+++ b/components/performance_manager/DEPS
@@ -4,5 +4,4 @@
   "+content/public/test",
   "+mojo/public",
   "+services/metrics/public/cpp",
-  "+services/resource_coordinator/public",
 ]
diff --git a/components/performance_manager/graph/frame_node_impl.cc b/components/performance_manager/graph/frame_node_impl.cc
index 303556e..8b68840c 100644
--- a/components/performance_manager/graph/frame_node_impl.cc
+++ b/components/performance_manager/graph/frame_node_impl.cc
@@ -45,8 +45,7 @@
 }
 
 void FrameNodeImpl::Bind(
-    mojo::PendingReceiver<resource_coordinator::mojom::DocumentCoordinationUnit>
-        receiver) {
+    mojo::PendingReceiver<mojom::DocumentCoordinationUnit> receiver) {
   // It is possible to receive a mojo::PendingReceiver<DocumentCoordinationUnit>
   // when |receiver_| is already bound in these cases:
   // - Navigation from the initial empty document to the first real document.
@@ -61,8 +60,7 @@
   document_.network_almost_idle.SetAndMaybeNotify(this, true);
 }
 
-void FrameNodeImpl::SetLifecycleState(
-    resource_coordinator::mojom::LifecycleState state) {
+void FrameNodeImpl::SetLifecycleState(mojom::LifecycleState state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   lifecycle_state_.SetAndMaybeNotify(this, state);
 }
@@ -73,7 +71,7 @@
 }
 
 void FrameNodeImpl::SetOriginTrialFreezePolicy(
-    resource_coordinator::mojom::InterventionPolicy policy) {
+    mojom::InterventionPolicy policy) {
   document_.origin_trial_freeze_policy.SetAndMaybeNotify(this, policy);
 }
 
@@ -130,14 +128,12 @@
   return child_frame_nodes_;
 }
 
-resource_coordinator::mojom::LifecycleState FrameNodeImpl::lifecycle_state()
-    const {
+mojom::LifecycleState FrameNodeImpl::lifecycle_state() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return lifecycle_state_.value();
 }
 
-resource_coordinator::mojom::InterventionPolicy
-FrameNodeImpl::origin_trial_freeze_policy() const {
+mojom::InterventionPolicy FrameNodeImpl::origin_trial_freeze_policy() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return document_.origin_trial_freeze_policy.value();
 }
@@ -481,7 +477,7 @@
   // Network is busy on navigation.
   network_almost_idle.SetAndMaybeNotify(frame_node, false);
   origin_trial_freeze_policy.SetAndMaybeNotify(
-      frame_node, resource_coordinator::mojom::InterventionPolicy::kUnknown);
+      frame_node, mojom::InterventionPolicy::kUnknown);
 }
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/graph/frame_node_impl.h b/components/performance_manager/graph/frame_node_impl.h
index c4ea1c0..58bbe1ca 100644
--- a/components/performance_manager/graph/frame_node_impl.h
+++ b/components/performance_manager/graph/frame_node_impl.h
@@ -48,7 +48,7 @@
 class FrameNodeImpl
     : public PublicNodeImpl<FrameNodeImpl, FrameNode>,
       public TypedNodeBase<FrameNodeImpl, FrameNode, FrameNodeObserver>,
-      public resource_coordinator::mojom::DocumentCoordinationUnit {
+      public mojom::DocumentCoordinationUnit {
  public:
   static constexpr NodeTypeEnum Type() { return NodeTypeEnum::kFrame; }
 
@@ -67,15 +67,13 @@
                 int32_t site_instance_id);
   ~FrameNodeImpl() override;
 
-  void Bind(mojo::PendingReceiver<
-            resource_coordinator::mojom::DocumentCoordinationUnit> receiver);
+  void Bind(mojo::PendingReceiver<mojom::DocumentCoordinationUnit> receiver);
 
-  // resource_coordinator::mojom::DocumentCoordinationUnit implementation.
+  // mojom::DocumentCoordinationUnit implementation.
   void SetNetworkAlmostIdle() override;
   void SetLifecycleState(LifecycleState state) override;
   void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload) override;
-  void SetOriginTrialFreezePolicy(
-      resource_coordinator::mojom::InterventionPolicy policy) override;
+  void SetOriginTrialFreezePolicy(mojom::InterventionPolicy policy) override;
   void SetIsAdFrame() override;
   void OnNonPersistentNotificationCreated() override;
 
@@ -170,10 +168,9 @@
 
     // Opt-in or opt-out of freezing via origin trial.
     ObservedProperty::NotifiesOnlyOnChangesWithPreviousValue<
-        resource_coordinator::mojom::InterventionPolicy,
+        mojom::InterventionPolicy,
         &FrameNodeObserver::OnOriginTrialFreezePolicyChanged>
-        origin_trial_freeze_policy{
-            resource_coordinator::mojom::InterventionPolicy::kUnknown};
+        origin_trial_freeze_policy{mojom::InterventionPolicy::kUnknown};
   };
 
   // Invoked by subframes on joining/leaving the graph.
@@ -186,8 +183,7 @@
   bool HasFrameNodeInAncestors(FrameNodeImpl* frame_node) const;
   bool HasFrameNodeInDescendants(FrameNodeImpl* frame_node) const;
 
-  mojo::Receiver<resource_coordinator::mojom::DocumentCoordinationUnit>
-      receiver_{this};
+  mojo::Receiver<mojom::DocumentCoordinationUnit> receiver_{this};
 
   FrameNodeImpl* const parent_frame_node_;
   PageNodeImpl* const page_node_;
diff --git a/components/performance_manager/graph/frame_node_impl_unittest.cc b/components/performance_manager/graph/frame_node_impl_unittest.cc
index e7f3a98..70ae828 100644
--- a/components/performance_manager/graph/frame_node_impl_unittest.cc
+++ b/components/performance_manager/graph/frame_node_impl_unittest.cc
@@ -128,8 +128,7 @@
   MOCK_METHOD1(OnNetworkAlmostIdleChanged, void(const FrameNode*));
   MOCK_METHOD1(OnFrameLifecycleStateChanged, void(const FrameNode*));
   MOCK_METHOD2(OnOriginTrialFreezePolicyChanged,
-               void(const FrameNode*,
-                    const resource_coordinator::mojom::InterventionPolicy&));
+               void(const FrameNode*, const mojom::InterventionPolicy&));
   MOCK_METHOD2(OnURLChanged, void(const FrameNode*, const GURL&));
   MOCK_METHOD1(OnIsAdFrameChanged, void(const FrameNode*));
   MOCK_METHOD1(OnFrameIsHoldingWebLockChanged, void(const FrameNode*));
@@ -184,8 +183,7 @@
   // Invoke "SetLifecycleState" and expect an "OnFrameLifecycleStateChanged"
   // callback.
   EXPECT_CALL(obs, OnFrameLifecycleStateChanged(raw_frame_node));
-  frame_node->SetLifecycleState(
-      resource_coordinator::mojom::LifecycleState::kFrozen);
+  frame_node->SetLifecycleState(mojom::LifecycleState::kFrozen);
   testing::Mock::VerifyAndClear(&obs);
 
   // Invoke "OnNonPersistentNotificationCreated" and expect an
diff --git a/components/performance_manager/graph/node_base.h b/components/performance_manager/graph/node_base.h
index 562926bf..c8e36fca 100644
--- a/components/performance_manager/graph/node_base.h
+++ b/components/performance_manager/graph/node_base.h
@@ -19,7 +19,6 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
 
 namespace performance_manager {
 
diff --git a/components/performance_manager/graph/node_base_unittest.cc b/components/performance_manager/graph/node_base_unittest.cc
index 4e39b6c..0118c2c 100644
--- a/components/performance_manager/graph/node_base_unittest.cc
+++ b/components/performance_manager/graph/node_base_unittest.cc
@@ -8,7 +8,6 @@
 #include "components/performance_manager/graph/process_node_impl.h"
 #include "components/performance_manager/test_support/graph_test_harness.h"
 #include "components/performance_manager/test_support/mock_graphs.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace performance_manager {
diff --git a/components/performance_manager/graph/process_node_impl.cc b/components/performance_manager/graph/process_node_impl.cc
index 1d47ed6..2862e00 100644
--- a/components/performance_manager/graph/process_node_impl.cc
+++ b/components/performance_manager/graph/process_node_impl.cc
@@ -29,8 +29,7 @@
 }
 
 void ProcessNodeImpl::Bind(
-    mojo::PendingReceiver<resource_coordinator::mojom::ProcessCoordinationUnit>
-        receiver) {
+    mojo::PendingReceiver<mojom::ProcessCoordinationUnit> receiver) {
   // A RenderProcessHost can be reused if the backing process suddenly dies, in
   // which case we will receive a new receiver from the newly spawned process.
   receiver_.reset();
diff --git a/components/performance_manager/graph/process_node_impl.h b/components/performance_manager/graph/process_node_impl.h
index 4515a64..df56041 100644
--- a/components/performance_manager/graph/process_node_impl.h
+++ b/components/performance_manager/graph/process_node_impl.h
@@ -15,6 +15,7 @@
 #include "components/performance_manager/graph/node_base.h"
 #include "components/performance_manager/graph/properties.h"
 #include "components/performance_manager/public/graph/process_node.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
 #include "components/performance_manager/public/render_process_host_proxy.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -38,7 +39,7 @@
 class ProcessNodeImpl
     : public PublicNodeImpl<ProcessNodeImpl, ProcessNode>,
       public TypedNodeBase<ProcessNodeImpl, ProcessNode, ProcessNodeObserver>,
-      public resource_coordinator::mojom::ProcessCoordinationUnit {
+      public mojom::ProcessCoordinationUnit {
  public:
   static constexpr NodeTypeEnum Type() { return NodeTypeEnum::kProcess; }
 
@@ -46,10 +47,9 @@
 
   ~ProcessNodeImpl() override;
 
-  void Bind(mojo::PendingReceiver<
-            resource_coordinator::mojom::ProcessCoordinationUnit> receiver);
+  void Bind(mojo::PendingReceiver<mojom::ProcessCoordinationUnit> receiver);
 
-  // resource_coordinator::mojom::ProcessCoordinationUnit implementation:
+  // mojom::ProcessCoordinationUnit implementation:
   void SetExpectedTaskQueueingDuration(base::TimeDelta duration) override;
   void SetMainThreadTaskLoadIsLow(bool main_thread_task_load_is_low) override;
 
@@ -149,8 +149,7 @@
 
   void LeaveGraph() override;
 
-  mojo::Receiver<resource_coordinator::mojom::ProcessCoordinationUnit>
-      receiver_{this};
+  mojo::Receiver<mojom::ProcessCoordinationUnit> receiver_{this};
 
   base::TimeDelta cumulative_cpu_usage_;
   uint64_t private_footprint_kb_ = 0u;
diff --git a/components/performance_manager/performance_manager_tab_helper.cc b/components/performance_manager/performance_manager_tab_helper.cc
index 16df454..ea2e4a2 100644
--- a/components/performance_manager/performance_manager_tab_helper.cc
+++ b/components/performance_manager/performance_manager_tab_helper.cc
@@ -331,8 +331,7 @@
     content::RenderFrameHost* render_frame_host,
     const std::string& interface_name,
     mojo::ScopedMessagePipeHandle* interface_pipe) {
-  if (interface_name !=
-      resource_coordinator::mojom::DocumentCoordinationUnit::Name_)
+  if (interface_name != mojom::DocumentCoordinationUnit::Name_)
     return;
 
   // TODO(https://crbug.com/987445): Why else than due to speculative render
@@ -355,8 +354,7 @@
   }
 
   PostToGraph(FROM_HERE, &FrameNodeImpl::Bind, it->second.get(),
-              mojo::PendingReceiver<
-                  resource_coordinator::mojom::DocumentCoordinationUnit>(
+              mojo::PendingReceiver<mojom::DocumentCoordinationUnit>(
                   std::move(*interface_pipe)));
 }
 
diff --git a/components/performance_manager/public/graph/frame_node.h b/components/performance_manager/public/graph/frame_node.h
index 1116ec07..0f72b87 100644
--- a/components/performance_manager/public/graph/frame_node.h
+++ b/components/performance_manager/public/graph/frame_node.h
@@ -9,8 +9,8 @@
 #include "base/macros.h"
 #include "components/performance_manager/public/frame_priority/frame_priority.h"
 #include "components/performance_manager/public/graph/node.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
-#include "services/resource_coordinator/public/mojom/lifecycle.mojom.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
+#include "components/performance_manager/public/mojom/lifecycle.mojom.h"
 
 class GURL;
 
@@ -52,8 +52,8 @@
 // it.
 class FrameNode : public Node {
  public:
-  using LifecycleState = resource_coordinator::mojom::LifecycleState;
-  using InterventionPolicy = resource_coordinator::mojom::InterventionPolicy;
+  using LifecycleState = mojom::LifecycleState;
+  using InterventionPolicy = mojom::InterventionPolicy;
   using Observer = FrameNodeObserver;
   using PriorityAndReason = frame_priority::PriorityAndReason;
 
@@ -156,7 +156,7 @@
 // implement the entire interface.
 class FrameNodeObserver {
  public:
-  using InterventionPolicy = resource_coordinator::mojom::InterventionPolicy;
+  using InterventionPolicy = mojom::InterventionPolicy;
 
   FrameNodeObserver();
   virtual ~FrameNodeObserver();
diff --git a/components/performance_manager/public/graph/page_node.h b/components/performance_manager/public/graph/page_node.h
index 41bcd1e9..fcf56dd0 100644
--- a/components/performance_manager/public/graph/page_node.h
+++ b/components/performance_manager/public/graph/page_node.h
@@ -10,10 +10,10 @@
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "components/performance_manager/public/graph/node.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
+#include "components/performance_manager/public/mojom/lifecycle.mojom.h"
 #include "components/performance_manager/public/web_contents_proxy.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
-#include "services/resource_coordinator/public/mojom/lifecycle.mojom.h"
 
 class GURL;
 
@@ -27,8 +27,8 @@
 // Extensions.
 class PageNode : public Node {
  public:
-  using InterventionPolicy = resource_coordinator::mojom::InterventionPolicy;
-  using LifecycleState = resource_coordinator::mojom::LifecycleState;
+  using InterventionPolicy = mojom::InterventionPolicy;
+  using LifecycleState = mojom::LifecycleState;
   using Observer = PageNodeObserver;
   class ObserverDefaultImpl;
 
diff --git a/components/performance_manager/public/mojom/BUILD.gn b/components/performance_manager/public/mojom/BUILD.gn
new file mode 100644
index 0000000..2e99329
--- /dev/null
+++ b/components/performance_manager/public/mojom/BUILD.gn
@@ -0,0 +1,19 @@
+# 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom_component("mojom") {
+  output_prefix = "performace_manager_public_mojom"
+  macro_prefix = "PERFORMANCE_MANAGER_PUBLIC_MOJOM"
+
+  sources = [
+    "coordination_unit.mojom",
+    "lifecycle.mojom",
+  ]
+
+  public_deps = [
+    "//mojo/public/mojom/base",
+  ]
+}
diff --git a/components/performance_manager/public/mojom/OWNERS b/components/performance_manager/public/mojom/OWNERS
new file mode 100644
index 0000000..7e4c8d7
--- /dev/null
+++ b/components/performance_manager/public/mojom/OWNERS
@@ -0,0 +1,5 @@
+file://components/performance_manager/OWNERS
+
+# For IPC security review
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/services/resource_coordinator/public/mojom/coordination_unit.mojom b/components/performance_manager/public/mojom/coordination_unit.mojom
similarity index 94%
rename from services/resource_coordinator/public/mojom/coordination_unit.mojom
rename to components/performance_manager/public/mojom/coordination_unit.mojom
index bda67fab..b561091 100644
--- a/services/resource_coordinator/public/mojom/coordination_unit.mojom
+++ b/components/performance_manager/public/mojom/coordination_unit.mojom
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module resource_coordinator.mojom;
+module performance_manager.mojom;
 
 import "mojo/public/mojom/base/process_id.mojom";
 import "mojo/public/mojom/base/time.mojom";
-import "services/resource_coordinator/public/mojom/lifecycle.mojom";
+import "components/performance_manager/public/mojom/lifecycle.mojom";
 
 // Any new type here needs to be mirrored between coordination_unit_types.h and
 // coordination_unit.mojom, and have mappings between the two defined in
diff --git a/services/resource_coordinator/public/mojom/lifecycle.mojom b/components/performance_manager/public/mojom/lifecycle.mojom
similarity index 90%
rename from services/resource_coordinator/public/mojom/lifecycle.mojom
rename to components/performance_manager/public/mojom/lifecycle.mojom
index b7691cb..12c6696 100644
--- a/services/resource_coordinator/public/mojom/lifecycle.mojom
+++ b/components/performance_manager/public/mojom/lifecycle.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module resource_coordinator.mojom;
+module performance_manager.mojom;
 
 // A lifecycle unit (a page, frame, tab or application) can be in one of
 // these lifecycle states.
@@ -10,4 +10,4 @@
   kRunning,
   kFrozen,
   kDiscarded
-};
\ No newline at end of file
+};
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 3f4524c..aca3c59 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -18316,7 +18316,35 @@
       If this policy is not set, the browser will only begin attempts to save memory once it has detected that the amount of physical memory on its machine is low.''',
 
       'label': '''Set memory limit for Chrome instances''',
-    }
+    },
+    {
+      # TODO(https://crbug.com/1012400): Remove this policy in M86.
+      'id': 626,
+      'name': 'TLS13HardeningForLocalAnchorsEnabled',
+      'owners': ['file://net/ssl/OWNERS'],
+      'type': 'main',
+      'schema': {
+        'type': 'boolean',
+      },
+      'example_value': True,
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'supported_on': ['chrome.*:79-', 'chrome_os:79-', 'android:79-'],
+      'caption': '''Enable a TLS 1.3 security feature for local trust anchors.''',
+      'tags': ['system-security'],
+      'desc': '''This policy controls a security feature in TLS 1.3 which protects connections against downgrade attacks. It is backwards-compatible and will not affect connections to compliant TLS 1.2 servers or proxies. However, older versions of some TLS-intercepting proxies have an implementation flaw which causes them to be incompatible.
+
+      If this policy is set to True, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will enable these security protections for all connections.
+
+      If this policy is set to False or not set, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will disable these security protections for connections authenticated with locally-installed CA certificates. These protections are always enabled for connections authenticated with publicly-trusted CA certificates.
+
+      This policy may be used to test for any affected proxies and upgrade them. Affected proxies are expected to fail connections with an error code of ERR_TLS13_DOWNGRADE_DETECTED. A later version of <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will enable this option by default.
+
+      After it is enabled by default, administrators who need more time to upgrade affected proxies may use this policy to temporarily disable this security feature. This policy will be removed after version 85.
+      '''
+    },
   ],
 
   'messages': {
@@ -19137,6 +19165,6 @@
   ],
   'placeholders': [],
   'deleted_policy_ids': [412, 546, 562, 569],
-  'highest_id_currently_used': 625,
+  'highest_id_currently_used': 626,
   'highest_atomic_group_id_currently_used': 38
 }
diff --git a/components/previews/content/previews_optimization_guide_decider.cc b/components/previews/content/previews_optimization_guide_decider.cc
index 5b2d747..e39bc18 100644
--- a/components/previews/content/previews_optimization_guide_decider.cc
+++ b/components/previews/content/previews_optimization_guide_decider.cc
@@ -89,10 +89,11 @@
       registered_optimization_types_(GetOptimizationTypesToRegister()) {
   DCHECK(optimization_guide_decider_);
 
-  optimization_guide_decider_->RegisterOptimizationTypes(
+  optimization_guide_decider_->RegisterOptimizationTypesAndTargets(
       std::vector<optimization_guide::proto::OptimizationType>(
           registered_optimization_types_.begin(),
-          registered_optimization_types_.end()));
+          registered_optimization_types_.end()),
+      {optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD});
 }
 
 PreviewsOptimizationGuideDecider::~PreviewsOptimizationGuideDecider() = default;
diff --git a/components/previews/content/previews_optimization_guide_decider_unittest.cc b/components/previews/content/previews_optimization_guide_decider_unittest.cc
index d1a1275..f43fab1 100644
--- a/components/previews/content/previews_optimization_guide_decider_unittest.cc
+++ b/components/previews/content/previews_optimization_guide_decider_unittest.cc
@@ -29,12 +29,18 @@
   TestOptimizationGuideDecider() = default;
   ~TestOptimizationGuideDecider() override = default;
 
-  void RegisterOptimizationTypes(
-      std::vector<optimization_guide::proto::OptimizationType>
-          optimization_types) override {
+  void RegisterOptimizationTypesAndTargets(
+      const std::vector<optimization_guide::proto::OptimizationType>&
+          optimization_types,
+      const std::vector<optimization_guide::proto::OptimizationTarget>&
+          optimization_targets) override {
     registered_optimization_types_ =
         base::flat_set<optimization_guide::proto::OptimizationType>(
             optimization_types.begin(), optimization_types.end());
+
+    registered_optimization_targets_ =
+        base::flat_set<optimization_guide::proto::OptimizationTarget>(
+            optimization_targets.begin(), optimization_targets.end());
   }
 
   // Returns the optimization types registered with the Optimization Guide
@@ -44,6 +50,13 @@
     return registered_optimization_types_;
   }
 
+  // Returns the optimization targets registered with the Optimization Guide
+  // Decider.
+  base::flat_set<optimization_guide::proto::OptimizationTarget>
+  registered_optimization_targets() {
+    return registered_optimization_targets_;
+  }
+
   optimization_guide::OptimizationGuideDecision CanApplyOptimization(
       content::NavigationHandle* navigation_handle,
       optimization_guide::proto::OptimizationTarget optimization_target,
@@ -81,6 +94,11 @@
   base::flat_set<optimization_guide::proto::OptimizationType>
       registered_optimization_types_;
 
+  // The optimization targets that were registered with the Optimization Guide
+  // Decider.
+  base::flat_set<optimization_guide::proto::OptimizationTarget>
+      registered_optimization_targets_;
+
   std::map<std::tuple<GURL, optimization_guide::proto::OptimizationType>,
            std::tuple<optimization_guide::OptimizationGuideDecision,
                       optimization_guide::OptimizationMetadata>>
@@ -158,7 +176,7 @@
 };
 
 TEST_F(PreviewsOptimizationGuideDeciderTest,
-       InitializationRegistersCorrectOptimizationTypes) {
+       InitializationRegistersCorrectOptimizationTypesAndTargets) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
       {previews::features::kLitePageServerPreviews,
@@ -187,6 +205,17 @@
   EXPECT_TRUE(registered_optimization_types.find(
                   optimization_guide::proto::RESOURCE_LOADING) !=
               registered_optimization_types.end());
+
+  // We expect that the PAINFUL_PAGE_LOAD optimization target is always
+  // registered.
+  base::flat_set<optimization_guide::proto::OptimizationTarget>
+      registered_optimization_targets =
+          optimization_guide_decider()->registered_optimization_targets();
+  EXPECT_EQ(1u, registered_optimization_targets.size());
+  EXPECT_TRUE(
+      registered_optimization_targets.find(
+          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD) !=
+      registered_optimization_targets.end());
 }
 
 TEST_F(PreviewsOptimizationGuideDeciderTest,
@@ -218,6 +247,17 @@
   EXPECT_EQ(registered_optimization_types.find(
                 optimization_guide::proto::RESOURCE_LOADING),
             registered_optimization_types.end());
+
+  // We expect that the PAINFUL_PAGE_LOAD optimization target is always
+  // registered.
+  base::flat_set<optimization_guide::proto::OptimizationTarget>
+      registered_optimization_targets =
+          optimization_guide_decider()->registered_optimization_targets();
+  EXPECT_EQ(1u, registered_optimization_targets.size());
+  EXPECT_TRUE(
+      registered_optimization_targets.find(
+          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD) !=
+      registered_optimization_targets.end());
 }
 
 TEST_F(PreviewsOptimizationGuideDeciderTest,
diff --git a/components/remote_cocoa/app_shim/alert.h b/components/remote_cocoa/app_shim/alert.h
index 37aeaa38..c08f785 100644
--- a/components/remote_cocoa/app_shim/alert.h
+++ b/components/remote_cocoa/app_shim/alert.h
@@ -10,7 +10,8 @@
 #include "base/mac/scoped_nsobject.h"
 #include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h"
 #include "components/remote_cocoa/common/alert.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "ui/gfx/text_elider.h"
 
 @class AlertBridgeHelper;
@@ -24,7 +25,7 @@
  public:
   // Creates a new alert which controls its own lifetime. It will destroy itself
   // once its NSAlert goes away.
-  AlertBridge(mojom::AlertBridgeRequest bridge_request);
+  AlertBridge(mojo::PendingReceiver<mojom::AlertBridge> bridge_receiver);
 
   // Send the specified disposition via the Show callback, then destroy |this|.
   void SendResultAndDestroy(mojom::AlertDisposition disposition);
@@ -39,7 +40,7 @@
 
   // Handle being disconnected (e.g, because the alert was programmatically
   // dismissed).
-  void OnConnectionError();
+  void OnMojoDisconnect();
 
   // remote_cocoa::mojom::Alert:
   void Show(mojom::AlertBridgeInitParamsPtr params,
@@ -55,7 +56,7 @@
   // The callback to make when the dialog has finished running.
   ShowCallback callback_;
 
-  mojo::Binding<remote_cocoa::mojom::AlertBridge> mojo_binding_;
+  mojo::Receiver<remote_cocoa::mojom::AlertBridge> mojo_receiver_{this};
   base::WeakPtrFactory<AlertBridge> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(AlertBridge);
 };
diff --git a/components/remote_cocoa/app_shim/alert.mm b/components/remote_cocoa/app_shim/alert.mm
index 1ff74600..78f2069 100644
--- a/components/remote_cocoa/app_shim/alert.mm
+++ b/components/remote_cocoa/app_shim/alert.mm
@@ -259,12 +259,13 @@
 ////////////////////////////////////////////////////////////////////////////////
 // AlertBridge:
 
-AlertBridge::AlertBridge(mojom::AlertBridgeRequest bridge_request)
-    : mojo_binding_(this), weak_factory_(this) {
-  mojo_binding_.Bind(std::move(bridge_request),
-                     ui::WindowResizeHelperMac::Get()->task_runner());
-  mojo_binding_.set_connection_error_handler(base::BindOnce(
-      &AlertBridge::OnConnectionError, weak_factory_.GetWeakPtr()));
+AlertBridge::AlertBridge(
+    mojo::PendingReceiver<mojom::AlertBridge> bridge_receiver)
+    : weak_factory_(this) {
+  mojo_receiver_.Bind(std::move(bridge_receiver),
+                      ui::WindowResizeHelperMac::Get()->task_runner());
+  mojo_receiver_.set_disconnect_handler(base::BindOnce(
+      &AlertBridge::OnMojoDisconnect, weak_factory_.GetWeakPtr()));
 }
 
 AlertBridge::~AlertBridge() {
@@ -272,7 +273,7 @@
   [NSObject cancelPreviousPerformRequestsWithTarget:helper_.get()];
 }
 
-void AlertBridge::OnConnectionError() {
+void AlertBridge::OnMojoDisconnect() {
   // If the alert has been shown, then close the window, and |this| will delete
   // itself after the window is closed. Otherwise, just delete |this|
   // immediately.
diff --git a/components/remote_cocoa/app_shim/application_bridge.h b/components/remote_cocoa/app_shim/application_bridge.h
index f19c3a17..c6a0b1a 100644
--- a/components/remote_cocoa/app_shim/application_bridge.h
+++ b/components/remote_cocoa/app_shim/application_bridge.h
@@ -11,6 +11,8 @@
 #include "components/remote_cocoa/common/native_widget_ns_window.mojom.h"
 #include "components/remote_cocoa/common/native_widget_ns_window_host.mojom.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 
 namespace remote_cocoa {
 
@@ -40,9 +42,10 @@
       WebContentsNSViewCreateCallback web_conents_create_callback);
 
   // mojom::Application:
-  void CreateAlert(mojom::AlertBridgeRequest bridge_request) override;
-  void ShowColorPanel(mojom::ColorPanelRequest request,
-                      mojom::ColorPanelHostPtr host) override;
+  void CreateAlert(
+      mojo::PendingReceiver<mojom::AlertBridge> bridge_receiver) override;
+  void ShowColorPanel(mojo::PendingReceiver<mojom::ColorPanel> receiver,
+                      mojo::PendingRemote<mojom::ColorPanelHost> host) override;
   void CreateNativeWidgetNSWindow(
       uint64_t bridge_id,
       mojom::NativeWidgetNSWindowAssociatedRequest bridge_request,
diff --git a/components/remote_cocoa/app_shim/application_bridge.mm b/components/remote_cocoa/app_shim/application_bridge.mm
index 628196e..ed12068 100644
--- a/components/remote_cocoa/app_shim/application_bridge.mm
+++ b/components/remote_cocoa/app_shim/application_bridge.mm
@@ -10,7 +10,7 @@
 #include "components/remote_cocoa/app_shim/color_panel_bridge.h"
 #include "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
 #include "components/remote_cocoa/app_shim/native_widget_ns_window_host_helper.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/cocoa/remote_accessibility_api.h"
 
@@ -116,15 +116,17 @@
   web_conents_create_callback_ = web_conents_create_callback;
 }
 
-void ApplicationBridge::CreateAlert(mojom::AlertBridgeRequest bridge_request) {
+void ApplicationBridge::CreateAlert(
+    mojo::PendingReceiver<mojom::AlertBridge> bridge_receiver) {
   // The resulting object manages its own lifetime.
-  ignore_result(new AlertBridge(std::move(bridge_request)));
+  ignore_result(new AlertBridge(std::move(bridge_receiver)));
 }
 
-void ApplicationBridge::ShowColorPanel(mojom::ColorPanelRequest request,
-                                       mojom::ColorPanelHostPtr host) {
-  mojo::MakeStrongBinding(std::make_unique<ColorPanelBridge>(std::move(host)),
-                          std::move(request));
+void ApplicationBridge::ShowColorPanel(
+    mojo::PendingReceiver<mojom::ColorPanel> receiver,
+    mojo::PendingRemote<mojom::ColorPanelHost> host) {
+  mojo::MakeSelfOwnedReceiver(
+      std::make_unique<ColorPanelBridge>(std::move(host)), std::move(receiver));
 }
 
 void ApplicationBridge::CreateNativeWidgetNSWindow(
diff --git a/components/remote_cocoa/app_shim/color_panel_bridge.h b/components/remote_cocoa/app_shim/color_panel_bridge.h
index 0c767b4a..d063c5d 100644
--- a/components/remote_cocoa/app_shim/color_panel_bridge.h
+++ b/components/remote_cocoa/app_shim/color_panel_bridge.h
@@ -7,6 +7,8 @@
 
 #include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h"
 #include "components/remote_cocoa/common/color_panel.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace remote_cocoa {
 
@@ -15,7 +17,7 @@
 class REMOTE_COCOA_APP_SHIM_EXPORT ColorPanelBridge
     : public remote_cocoa::mojom::ColorPanel {
  public:
-  ColorPanelBridge(mojom::ColorPanelHostPtr host);
+  ColorPanelBridge(mojo::PendingRemote<mojom::ColorPanelHost> host);
   ~ColorPanelBridge() override;
   mojom::ColorPanelHost* host() { return host_.get(); }
 
@@ -24,7 +26,7 @@
   void SetSelectedColor(uint32_t color) override;
 
  private:
-  mojom::ColorPanelHostPtr host_;
+  mojo::Remote<mojom::ColorPanelHost> host_;
 };
 
 }  // namespace remote_cocoa
diff --git a/components/remote_cocoa/app_shim/color_panel_bridge.mm b/components/remote_cocoa/app_shim/color_panel_bridge.mm
index 12eaee1..eb2a87c 100644
--- a/components/remote_cocoa/app_shim/color_panel_bridge.mm
+++ b/components/remote_cocoa/app_shim/color_panel_bridge.mm
@@ -116,7 +116,8 @@
 
 namespace remote_cocoa {
 
-ColorPanelBridge::ColorPanelBridge(mojom::ColorPanelHostPtr host)
+ColorPanelBridge::ColorPanelBridge(
+    mojo::PendingRemote<mojom::ColorPanelHost> host)
     : host_(std::move(host)) {
   g_current_panel_bridge = this;
 }
diff --git a/components/remote_cocoa/common/application.mojom b/components/remote_cocoa/common/application.mojom
index 786e5f92..fa907f50 100644
--- a/components/remote_cocoa/common/application.mojom
+++ b/components/remote_cocoa/common/application.mojom
@@ -26,10 +26,11 @@
 // various Cocoa types (NSAlert, NSWindow, NSView, etc) are created.
 interface Application {
   // Create a bridge for an NSAlert. The resulting object owns its own lifetime.
-  CreateAlert(AlertBridge& alert_bridge_request);
+  CreateAlert(pending_receiver<AlertBridge> alert_bridge_receiver);
 
   // Show the NSColorPanel in this application.
-  ShowColorPanel(ColorPanel& request, ColorPanelHost host);
+  ShowColorPanel(pending_receiver<ColorPanel> receiver,
+                 pending_remote<ColorPanelHost> host);
 
   // Create a window for a native widget. The resulting object will be owned by
   // the connection for |host|. Closing that connection will result in deleting
diff --git a/components/safe_browsing/password_protection/metrics_util.cc b/components/safe_browsing/password_protection/metrics_util.cc
index ccce2ecd..28390f7 100644
--- a/components/safe_browsing/password_protection/metrics_util.cc
+++ b/components/safe_browsing/password_protection/metrics_util.cc
@@ -34,6 +34,8 @@
     "PasswordProtection.RequestOutcome.GSuiteSyncPasswordEntry";
 const char kGSuiteNonSyncPasswordEntryRequestOutcomeHistogram[] =
     "PasswordProtection.RequestOutcome.GSuiteNonSyncPasswordEntry";
+const char kSavedPasswordEntryRequestOutcomeHistogram[] =
+    "PasswordProtection.RequestOutcome.SavedPasswordEntry";
 const char kGSuiteSyncPasswordEntryVerdictHistogram[] =
     "PasswordProtection.Verdict.GSuiteSyncPasswordEntry";
 const char kGSuiteNonSyncPasswordEntryVerdictHistogram[] =
@@ -42,12 +44,16 @@
     "PasswordProtection.Verdict.GmailSyncPasswordEntry";
 const char kGmailNonSyncPasswordEntryVerdictHistogram[] =
     "PasswordProtection.Verdict.GmailNonSyncPasswordEntry";
+const char kSavedPasswordEntryVerdictHistogram[] =
+    "PasswordProtection.Verdict.SavedPasswordEntry";
 const char kGmailNonSyncPasswordInterstitialHistogram[] =
     "PasswordProtection.InterstitialAction.GmailNonSyncPasswordEntry";
 const char kGmailSyncPasswordPageInfoHistogram[] =
     "PasswordProtection.PageInfoAction.GmailSyncPasswordEntry";
 const char kGmailNonSyncPasswordPageInfoHistogram[] =
     "PasswordProtection.PageInfoAction.GmailNonSyncPasswordEntry";
+const char kSavedPasswordPageInfoHistogram[] =
+    "PasswordProtection.PageInfoAction.SavedPasswordEntry";
 const char kGmailSyncPasswordWarningDialogHistogram[] =
     "PasswordProtection.ModalWarningDialogAction.GmailSyncPasswordEntry";
 const char kGmailNonSyncPasswordWarningDialogHistogram[] =
@@ -69,6 +75,8 @@
     "PasswordProtection.ModalWarningDialogAction.GSuiteSyncPasswordEntry";
 const char kGSuiteNonSyncPasswordWarningDialogHistogram[] =
     "PasswordProtection.ModalWarningDialogAction.GSuiteNonSyncPasswordEntry";
+const char kSavedPasswordWarningDialogHistogram[] =
+    "PasswordProtection.ModalWarningDialogAction.SavedPasswordEntry";
 const char kNonSyncPasswordWarningDialogHistogram[] =
     "PasswordProtection.ModalWarningDialogAction.NonSyncPasswordEntry";
 const char kPasswordOnFocusRequestOutcomeHistogram[] =
@@ -121,6 +129,10 @@
              ReusedPasswordAccountType::NON_GAIA_ENTERPRISE) {
     UMA_HISTOGRAM_ENUMERATION(kEnterprisePasswordEntryRequestOutcomeHistogram,
                               outcome);
+  } else if (password_account_type.account_type() ==
+             ReusedPasswordAccountType::SAVED_PASSWORD) {
+    UMA_HISTOGRAM_ENUMERATION(kSavedPasswordEntryRequestOutcomeHistogram,
+                              outcome);
   } else {
     if (is_gsuite_user) {
       UMA_HISTOGRAM_ENUMERATION(
@@ -222,6 +234,11 @@
         UMA_HISTOGRAM_ENUMERATION(
             kEnterprisePasswordEntryVerdictHistogram, verdict_type,
             (LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1));
+      } else if (password_account_type.account_type() ==
+                 ReusedPasswordAccountType::SAVED_PASSWORD) {
+        UMA_HISTOGRAM_ENUMERATION(
+            kSavedPasswordEntryVerdictHistogram, verdict_type,
+            (LoginReputationClientResponse_VerdictType_VerdictType_MAX + 1));
       }
       break;
     default:
@@ -276,6 +293,9 @@
       } else if (password_account_type.account_type() ==
                  ReusedPasswordAccountType::NON_GAIA_ENTERPRISE) {
         UMA_HISTOGRAM_ENUMERATION(kEnterprisePasswordPageInfoHistogram, action);
+      } else if (password_account_type.account_type() ==
+                 ReusedPasswordAccountType::SAVED_PASSWORD) {
+        UMA_HISTOGRAM_ENUMERATION(kSavedPasswordPageInfoHistogram, action);
       } else {
         UMA_HISTOGRAM_ENUMERATION(kNonSyncPasswordPageInfoHistogram, action);
         if (is_gsuite_user) {
@@ -301,6 +321,9 @@
                  ReusedPasswordAccountType::NON_GAIA_ENTERPRISE) {
         UMA_HISTOGRAM_ENUMERATION(kEnterprisePasswordWarningDialogHistogram,
                                   action);
+      } else if (password_account_type.account_type() ==
+                 ReusedPasswordAccountType::SAVED_PASSWORD) {
+        UMA_HISTOGRAM_ENUMERATION(kSavedPasswordWarningDialogHistogram, action);
       } else {
         UMA_HISTOGRAM_ENUMERATION(kNonSyncPasswordWarningDialogHistogram,
                                   action);
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc
index 15c5ccd1f..96c96e1 100644
--- a/components/search_engines/template_url.cc
+++ b/components/search_engines/template_url.cc
@@ -386,6 +386,11 @@
     query_params.push_back(search_terms_args.additional_query_params);
   if (!gurl.query().empty())
     query_params.push_back(gurl.query());
+  if (owner_->created_from_play_api()) {
+    // Append attribution parameter to query originating from Play API search
+    // engine.
+    query_params.push_back("chrome_dse_attribution=1");
+  }
 
   if (query_params.empty())
     return url;
diff --git a/components/search_engines/template_url_unittest.cc b/components/search_engines/template_url_unittest.cc
index a19a834..a96c8a0 100644
--- a/components/search_engines/template_url_unittest.cc
+++ b/components/search_engines/template_url_unittest.cc
@@ -802,6 +802,33 @@
   }
 }
 
+// Tests appending attribution parameter to queries originating from Play API
+// search engine.
+TEST_F(TemplateURLTest, PlayAPIAttribution) {
+  const struct TestData {
+    const char* url;
+    base::string16 terms;
+    bool created_from_play_api;
+    const char* output;
+  } test_data[] = {{"http://foo/?q={searchTerms}", ASCIIToUTF16("bar"), false,
+                    "http://foo/?q=bar"},
+                   {"http://foo/?q={searchTerms}", ASCIIToUTF16("bar"), true,
+                    "http://foo/?q=bar&chrome_dse_attribution=1"}};
+  TemplateURLData data;
+  for (size_t i = 0; i < base::size(test_data); ++i) {
+    data.SetURL(test_data[i].url);
+    data.created_from_play_api = test_data[i].created_from_play_api;
+    TemplateURL url(data);
+    EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
+    ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
+    GURL result(url.url_ref().ReplaceSearchTerms(
+        TemplateURLRef::SearchTermsArgs(test_data[i].terms),
+        search_terms_data_));
+    ASSERT_TRUE(result.is_valid());
+    EXPECT_EQ(test_data[i].output, result.spec());
+  }
+}
+
 TEST_F(TemplateURLTest, Suggestions) {
   struct TestData {
     const int accepted_suggestion;
diff --git a/components/services/leveldb/BUILD.gn b/components/services/leveldb/BUILD.gn
index ee3fba3a..624c887 100644
--- a/components/services/leveldb/BUILD.gn
+++ b/components/services/leveldb/BUILD.gn
@@ -21,22 +21,3 @@
     "//third_party/leveldatabase",
   ]
 }
-
-test("leveldb_service_unittests") {
-  sources = [
-    "leveldb_mojo_unittest.cc",
-  ]
-
-  deps = [
-    ":lib",
-    "//base",
-    "//base/test:test_support",
-    "//components/services/leveldb/public/cpp",
-    "//components/services/leveldb/public/mojom",
-    "//mojo/core/test:run_all_unittests",
-    "//mojo/public/cpp/bindings",
-    "//mojo/public/cpp/system",
-    "//testing/gtest",
-    "//third_party/leveldatabase",
-  ]
-}
diff --git a/components/services/leveldb/leveldb.typemap b/components/services/leveldb/leveldb.typemap
deleted file mode 100644
index 1af5cdf..0000000
--- a/components/services/leveldb/leveldb.typemap
+++ /dev/null
@@ -1,16 +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.
-
-mojom = "//components/services/leveldb/public/mojom/leveldb.mojom"
-public_headers = [ "//third_party/leveldatabase/env_chromium.h" ]
-traits_headers = [ "//components/services/leveldb/leveldb_mojom_traits.h" ]
-sources = [
-  "//components/services/leveldb/leveldb_mojom_traits.cc",
-]
-deps = []
-public_deps = [
-  "//mojo/public/cpp/bindings",
-  "//third_party/leveldatabase",
-]
-type_mappings = [ "leveldb.mojom.OpenOptions=::leveldb_env::Options" ]
diff --git a/components/services/leveldb/leveldb_database_impl.cc b/components/services/leveldb/leveldb_database_impl.cc
index 9f6042b..991d1d9e 100644
--- a/components/services/leveldb/leveldb_database_impl.cc
+++ b/components/services/leveldb/leveldb_database_impl.cc
@@ -30,7 +30,7 @@
     const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>&
         memory_dump_id,
     scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
-    OpenCallback callback) {
+    StatusCallback callback) {
   std::unique_ptr<LevelDBDatabaseImpl> db(new LevelDBDatabaseImpl);
   storage::DomStorageDatabase::OpenDirectory(
       directory, dbname, options, memory_dump_id,
@@ -46,7 +46,7 @@
         memory_dump_id,
     const std::string& tracking_name,
     scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
-    OpenCallback callback) {
+    StatusCallback callback) {
   std::unique_ptr<LevelDBDatabaseImpl> db(new LevelDBDatabaseImpl);
   storage::DomStorageDatabase::OpenInMemory(
       tracking_name, memory_dump_id, std::move(blocking_task_runner),
@@ -61,7 +61,7 @@
 
 void LevelDBDatabaseImpl::Put(const std::vector<uint8_t>& key,
                               const std::vector<uint8_t>& value,
-                              PutCallback callback) {
+                              StatusCallback callback) {
   RunDatabaseTask(
       base::BindOnce(
           [](const std::vector<uint8_t>& key, const std::vector<uint8_t>& value,
@@ -73,7 +73,7 @@
 }
 
 void LevelDBDatabaseImpl::Delete(const std::vector<uint8_t>& key,
-                                 DeleteCallback callback) {
+                                 StatusCallback callback) {
   RunDatabaseTask(base::BindOnce(
                       [](const std::vector<uint8_t>& key,
                          const storage::DomStorageDatabase& db) {
@@ -84,7 +84,7 @@
 }
 
 void LevelDBDatabaseImpl::DeletePrefixed(const std::vector<uint8_t>& key_prefix,
-                                         DeletePrefixedCallback callback) {
+                                         StatusCallback callback) {
   RunDatabaseTask(base::BindOnce(
                       [](const std::vector<uint8_t>& prefix,
                          const storage::DomStorageDatabase& db) {
@@ -98,12 +98,12 @@
                   std::move(callback));
 }
 
-void LevelDBDatabaseImpl::RewriteDB(RewriteDBCallback callback) {
+void LevelDBDatabaseImpl::RewriteDB(StatusCallback callback) {
   DCHECK(database_);
   database_.PostTaskWithThisObject(
       FROM_HERE,
       base::BindOnce(
-          [](RewriteDBCallback callback,
+          [](StatusCallback callback,
              scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
              storage::DomStorageDatabase* db) {
             callback_task_runner->PostTask(
@@ -116,7 +116,7 @@
 
 void LevelDBDatabaseImpl::Write(
     std::vector<mojom::BatchedOperationPtr> operations,
-    WriteCallback callback) {
+    StatusCallback callback) {
   RunDatabaseTask(
       base::BindOnce(
           [](std::vector<mojom::BatchedOperationPtr> operations,
@@ -251,7 +251,7 @@
 void LevelDBDatabaseImpl::CopyPrefixed(
     const std::vector<uint8_t>& source_key_prefix,
     const std::vector<uint8_t>& destination_key_prefix,
-    CopyPrefixedCallback callback) {
+    StatusCallback callback) {
   RunDatabaseTask(base::BindOnce(
                       [](const std::vector<uint8_t>& prefix,
                          const std::vector<uint8_t>& new_prefix,
@@ -268,7 +268,7 @@
 }
 
 void LevelDBDatabaseImpl::OnDatabaseOpened(
-    OpenCallback callback,
+    StatusCallback callback,
     base::SequenceBound<storage::DomStorageDatabase> database,
     leveldb::Status status) {
   database_ = std::move(database);
diff --git a/components/services/leveldb/leveldb_database_impl.h b/components/services/leveldb/leveldb_database_impl.h
index b9820632..8b32fb4 100644
--- a/components/services/leveldb/leveldb_database_impl.h
+++ b/components/services/leveldb/leveldb_database_impl.h
@@ -21,17 +21,15 @@
 namespace leveldb {
 
 // A temporary wrapper around the Storage Service's DomStorageDatabase class,
-// implemented behind the mojom interface facade consumed by
-// LocalStorageContextMojo, SessionStorageContextMojo, and related classes. Note
-// that this is never used through an actual message pipe, but always via direct
-// method calls.
+// consumed by LocalStorageContextMojo, SessionStorageContextMojo, and related
+// classes.
 //
 // TODO(https://crbug.com/1000959): Delete this class.
-class LevelDBDatabaseImpl : public mojom::LevelDBDatabase {
+class LevelDBDatabaseImpl {
  public:
-  using OpenCallback = base::OnceCallback<void(mojom::DatabaseError)>;
+  using StatusCallback = base::OnceCallback<void(mojom::DatabaseError)>;
 
-  ~LevelDBDatabaseImpl() override;
+  ~LevelDBDatabaseImpl();
 
   static std::unique_ptr<LevelDBDatabaseImpl> OpenDirectory(
       const leveldb_env::Options& options,
@@ -40,14 +38,14 @@
       const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>&
           memory_dump_id,
       scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
-      OpenCallback callback);
+      StatusCallback callback);
 
   static std::unique_ptr<LevelDBDatabaseImpl> OpenInMemory(
       const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>&
           memory_dump_id,
       const std::string& tracking_name,
       scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
-      OpenCallback callback);
+      StatusCallback callback);
 
   base::SequenceBound<storage::DomStorageDatabase>& database() {
     return database_;
@@ -59,29 +57,43 @@
   // Overridden from LevelDBDatabase:
   void Put(const std::vector<uint8_t>& key,
            const std::vector<uint8_t>& value,
-           PutCallback callback) override;
-  void Delete(const std::vector<uint8_t>& key,
-              DeleteCallback callback) override;
+           StatusCallback callback);
+
+  void Delete(const std::vector<uint8_t>& key, StatusCallback callback);
+
   void DeletePrefixed(const std::vector<uint8_t>& key_prefix,
-                      DeletePrefixedCallback callback) override;
-  void RewriteDB(RewriteDBCallback callback) override;
+                      StatusCallback callback);
+
+  void RewriteDB(StatusCallback callback);
+
   void Write(std::vector<mojom::BatchedOperationPtr> operations,
-             WriteCallback callback) override;
-  void Get(const std::vector<uint8_t>& key, GetCallback callback) override;
+             StatusCallback callback);
+
+  using GetCallback = base::OnceCallback<void(mojom::DatabaseError status,
+                                              const std::vector<uint8_t>&)>;
+  void Get(const std::vector<uint8_t>& key, GetCallback callback);
+
+  using GetPrefixedCallback =
+      base::OnceCallback<void(mojom::DatabaseError status,
+                              std::vector<mojom::KeyValuePtr>)>;
   void GetPrefixed(const std::vector<uint8_t>& key_prefix,
-                   GetPrefixedCallback callback) override;
+                   GetPrefixedCallback callback);
+
+  using GetManyCallback =
+      base::OnceCallback<void(std::vector<mojom::GetManyResultPtr>)>;
   void GetMany(std::vector<mojom::GetManyRequestPtr> keys_or_prefixes,
-               GetManyCallback callback) override;
+               GetManyCallback callback);
+
   void CopyPrefixed(const std::vector<uint8_t>& source_key_prefix,
                     const std::vector<uint8_t>& destination_key_prefix,
-                    CopyPrefixedCallback callback) override;
+                    StatusCallback callback);
 
  private:
   using StatusAndKeyValues =
       std::tuple<Status, std::vector<mojom::KeyValuePtr>>;
 
   void OnDatabaseOpened(
-      OpenCallback callback,
+      StatusCallback callback,
       base::SequenceBound<storage::DomStorageDatabase> database,
       leveldb::Status status);
 
diff --git a/components/services/leveldb/leveldb_mojo_unittest.cc b/components/services/leveldb/leveldb_mojo_unittest.cc
deleted file mode 100644
index 8a1efefc..0000000
--- a/components/services/leveldb/leveldb_mojo_unittest.cc
+++ /dev/null
@@ -1,36 +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 "components/services/leveldb/leveldb_mojom_traits.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/leveldatabase/leveldb_chrome.h"
-
-namespace {
-
-class LevelDBServiceMojoTest : public testing::Test {};
-
-}  // namespace
-
-TEST(LevelDBServiceMojoTest, TestSerialization) {
-  leveldb_env::Options input;
-  // Tweak all input values to have a non-default value.
-  input.create_if_missing = !input.create_if_missing;
-  input.error_if_exists = !input.error_if_exists;
-  input.paranoid_checks = !input.paranoid_checks;
-  input.write_buffer_size += 1;
-  input.max_open_files += 1;
-  input.block_cache = leveldb_chrome::GetSharedWebBlockCache();
-
-  leveldb_env::Options output;
-  ASSERT_TRUE(leveldb::mojom::OpenOptions::Deserialize(
-      leveldb::mojom::OpenOptions::Serialize(&input), &output));
-
-  EXPECT_EQ(output.create_if_missing, output.create_if_missing);
-  EXPECT_EQ(output.error_if_exists, output.error_if_exists);
-  EXPECT_EQ(output.paranoid_checks, output.paranoid_checks);
-  EXPECT_EQ(output.write_buffer_size, output.write_buffer_size);
-  EXPECT_EQ(output.max_open_files, output.max_open_files);
-  EXPECT_EQ(leveldb_chrome::GetSharedWebBlockCache(), output.block_cache);
-}
diff --git a/components/services/leveldb/leveldb_mojom_traits.cc b/components/services/leveldb/leveldb_mojom_traits.cc
deleted file mode 100644
index 0403c35..0000000
--- a/components/services/leveldb/leveldb_mojom_traits.cc
+++ /dev/null
@@ -1,80 +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 "components/services/leveldb/leveldb_mojom_traits.h"
-
-#include "third_party/leveldatabase/env_chromium.h"
-#include "third_party/leveldatabase/leveldb_chrome.h"
-
-namespace mojo {
-
-bool StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>::
-    create_if_missing(const leveldb_env::Options& options) {
-  return options.create_if_missing;
-}
-
-bool StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>::
-    error_if_exists(const leveldb_env::Options& options) {
-  return options.error_if_exists;
-}
-
-bool StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>::
-    paranoid_checks(const leveldb_env::Options& options) {
-  return options.paranoid_checks;
-}
-
-uint64_t
-StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>::
-    write_buffer_size(const leveldb_env::Options& options) {
-  return options.write_buffer_size;
-}
-
-int32_t StructTraits<
-    leveldb::mojom::OpenOptionsDataView,
-    leveldb_env::Options>::max_open_files(const leveldb_env::Options& options) {
-  return options.max_open_files;
-}
-
-leveldb::mojom::SharedReadCache
-StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>::
-    shared_block_read_cache(const leveldb_env::Options& options) {
-  // The Mojo wrapper for leveldb only supports using one of two different
-  // shared caches. Chrome's Mojo wrapper does not currently support custom
-  // caches, nor nullptr to have leveldb create the block read cache.
-  if (!options.block_cache) {
-    // Specify either Default or Web.
-    NOTREACHED();
-    return leveldb::mojom::SharedReadCache::Default;
-  }
-  if (options.block_cache == leveldb_chrome::GetSharedWebBlockCache())
-    return leveldb::mojom::SharedReadCache::Web;
-
-  leveldb_env::Options default_options;
-  // If failing see comment above.
-  DCHECK_EQ(default_options.block_cache, options.block_cache);
-
-  return leveldb::mojom::SharedReadCache::Default;
-}
-
-bool StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>::
-    Read(leveldb::mojom::OpenOptionsDataView data, leveldb_env::Options* out) {
-  out->create_if_missing = data.create_if_missing();
-  out->error_if_exists = data.error_if_exists();
-  out->paranoid_checks = data.paranoid_checks();
-  out->write_buffer_size = data.write_buffer_size();
-  out->max_open_files = data.max_open_files();
-  switch (data.shared_block_read_cache()) {
-    case leveldb::mojom::SharedReadCache::Default: {
-      leveldb_env::Options options;
-      out->block_cache = options.block_cache;
-    } break;
-    case leveldb::mojom::SharedReadCache::Web:
-      out->block_cache = leveldb_chrome::GetSharedWebBlockCache();
-      break;
-  }
-
-  return true;
-}
-
-}  // namespace mojo
diff --git a/components/services/leveldb/leveldb_mojom_traits.h b/components/services/leveldb/leveldb_mojom_traits.h
deleted file mode 100644
index 2bbfafd..0000000
--- a/components/services/leveldb/leveldb_mojom_traits.h
+++ /dev/null
@@ -1,27 +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 COMPONENTS_SERVICES_LEVELDB_LEVELDB_MOJOM_TRAITS_H_
-#define COMPONENTS_SERVICES_LEVELDB_LEVELDB_MOJOM_TRAITS_H_
-
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
-
-namespace mojo {
-
-template <>
-struct StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options> {
-  static bool create_if_missing(const leveldb_env::Options& options);
-  static bool error_if_exists(const leveldb_env::Options& options);
-  static bool paranoid_checks(const leveldb_env::Options& options);
-  static uint64_t write_buffer_size(const leveldb_env::Options& options);
-  static int32_t max_open_files(const leveldb_env::Options& options);
-  static ::leveldb::mojom::SharedReadCache shared_block_read_cache(
-      const leveldb_env::Options& options);
-  static bool Read(::leveldb::mojom::OpenOptionsDataView data,
-                   leveldb_env::Options* out);
-};
-
-}  // namespace mojo
-
-#endif  // COMPONENTS_SERVICES_LEVELDB_LEVELDB_MOJOM_TRAITS_H_
diff --git a/components/services/leveldb/public/mojom/BUILD.gn b/components/services/leveldb/public/mojom/BUILD.gn
index f64838e..6434221 100644
--- a/components/services/leveldb/public/mojom/BUILD.gn
+++ b/components/services/leveldb/public/mojom/BUILD.gn
@@ -5,13 +5,7 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 
 mojom("mojom") {
-  support_lazy_serialization = true
-
   sources = [
     "leveldb.mojom",
   ]
-
-  public_deps = [
-    "//mojo/public/mojom/base",
-  ]
 }
diff --git a/components/services/leveldb/public/mojom/leveldb.mojom b/components/services/leveldb/public/mojom/leveldb.mojom
index 9381ebd..e008482 100644
--- a/components/services/leveldb/public/mojom/leveldb.mojom
+++ b/components/services/leveldb/public/mojom/leveldb.mojom
@@ -4,8 +4,6 @@
 
 module leveldb.mojom;
 
-import "mojo/public/mojom/base/unguessable_token.mojom";
-
 enum DatabaseError {
   OK,
   NOT_FOUND,
@@ -47,85 +45,3 @@
   array<uint8> key_value;
 };
 
-enum SharedReadCache {
-  Default,
-  Web,
-};
-
-// Options which control the behavior of a database. (This struct corresponds
-// with the struct in leveldb's options.h.)
-//
-// Note: This struct does not have default values. The values are set by a
-// struct trait which copies values to/from a leveldb_env::Options instance.
-struct OpenOptions {
-  // TODO(erg): Find all comparators and copy them into the service.
-
-  // If true, the database will be created if it is missing.
-  bool create_if_missing;
-
-  // If true, an error is raised if the database already exists.
-  bool error_if_exists;
-
-  // If true, the implementation will do aggressive checking of the
-  // data it is processing and will stop early if it detects any
-  // errors.
-  bool paranoid_checks;
-
-  // Amount of data to build up in memory (backed by an unsorted log
-  // on disk) before converting to a sorted on-disk file.
-  uint64 write_buffer_size;
-
-  // Number of open files that can be used by the DB.
-  int32 max_open_files;
-
-  // The shared read cache to use.
-  SharedReadCache shared_block_read_cache = SharedReadCache.Default;
-};
-
-// A leveldb database.
-interface LevelDBDatabase {
-  // Basic Interface -------------------------------------------------------
-
-  // Sets the database entry for "key" to "value". Returns OK on success.
-  Put(array<uint8> key, array<uint8> value) => (DatabaseError status);
-
-  // Remove the database entry (if any) for "key".  Returns OK on
-  // success, and a non-OK status on error.  It is not an error if "key"
-  // did not exist in the database.
-  Delete(array<uint8> key) => (DatabaseError status);
-
-  DeletePrefixed(array<uint8> key_prefix) => (DatabaseError status);
-
-  // Rewrites the database to remove traces of deleted entries from disk.
-  // Returns OK on success. A non-OK error means that the rewrite failed.
-  // If the status is not OK, the database can become unusable which will close
-  // the mojo connection.
-  RewriteDB() => (DatabaseError status);
-
-  // Atomically performs all |operations|.
-  // The DELETE_PREFIXED_KEY applies to all keys that exist before these
-  // operations execute. If a 'put' operation precedes a delete prefix, then it
-  // will only be deleted if it was a previously-populated key in the database.
-  // The COPY_PREFIXED_KEY operations will always ignore all other changes in
-  // the operations batch. It will not copy records that were inserted earlier
-  // in the operations list.
-  Write(array<BatchedOperation> operations) => (DatabaseError status);
-
-  Get(array<uint8> key) => (DatabaseError status, array<uint8> value);
-
-  GetPrefixed(array<uint8> key_prefix)
-      => (DatabaseError status, array<KeyValue> data);
-
-  // Get multiple keys and key prefixes and return corresponding values or
-  // non-OK error in the same order. Each request has a corresponding result
-  // in the same array position. A result can only be either a non-OK
-  // db status or a value for the key or key prefix.
-  GetMany(array<GetManyRequest> keys_or_prefixes)
-      => (array<GetManyResult> data);
-
-  // Copies all data from the source prefix to the destination prefix. Useful
-  // for deep copies.
-  CopyPrefixed(array<uint8> source_key_prefix,
-               array<uint8> destination_key_prefix)
-      => (DatabaseError status);
-};
diff --git a/components/services/storage/dom_storage/dom_storage_database.cc b/components/services/storage/dom_storage/dom_storage_database.cc
index eddd4b1c..43ee71d 100644
--- a/components/services/storage/dom_storage/dom_storage_database.cc
+++ b/components/services/storage/dom_storage/dom_storage_database.cc
@@ -185,6 +185,8 @@
 DomStorageDatabase::~DomStorageDatabase() {
   base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
       this);
+  if (destruction_callback_)
+    std::move(destruction_callback_).Run();
 }
 
 // static
@@ -337,6 +339,8 @@
     leveldb::WriteBatch* batch) const {
   if (!db_)
     return Status::IOError(kInvalidDatabaseMessage);
+  if (fail_commits_for_testing_)
+    return Status::IOError("Simulated I/O Error");
   return db_->Write(leveldb::WriteOptions(), batch);
 }
 
diff --git a/components/services/storage/dom_storage/dom_storage_database.h b/components/services/storage/dom_storage/dom_storage_database.h
index 18e3e8e..ffe142c3 100644
--- a/components/services/storage/dom_storage/dom_storage_database.h
+++ b/components/services/storage/dom_storage/dom_storage_database.h
@@ -146,6 +146,12 @@
   // usable; in such cases, all future operations will return an IOError status.
   Status RewriteDB();
 
+  void SetDestructionCallbackForTesting(base::OnceClosure callback) {
+    destruction_callback_ = std::move(callback);
+  }
+
+  void MakeAllCommitsFailForTesting() { fail_commits_for_testing_ = true; }
+
  private:
   friend class base::SequenceBound<DomStorageDatabase>;
 
@@ -194,6 +200,13 @@
       memory_dump_id_;
   std::unique_ptr<leveldb::DB> db_;
 
+  // Causes all calls to |Commit()| to fail with an IOError for simulated
+  // disk failures in testing.
+  bool fail_commits_for_testing_ = false;
+
+  // Callback to run on destruction in tests.
+  base::OnceClosure destruction_callback_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(DomStorageDatabase);
diff --git a/components/translate/content/DEPS b/components/translate/content/DEPS
index 83c2ce4..c57486b 100644
--- a/components/translate/content/DEPS
+++ b/components/translate/content/DEPS
@@ -1,6 +1,4 @@
 include_rules = [
   "+content/public/common",
   "+mojo/public",
-  "+services/network/public",
-  "+third_party/blink/public",
 ]
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc
index 94f2d1b..4deac26 100644
--- a/components/translate/content/browser/content_translate_driver.cc
+++ b/components/translate/content/browser/content_translate_driver.cc
@@ -21,7 +21,6 @@
 #include "components/translate/content/browser/content_record_page_language.h"
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "components/translate/core/browser/translate_manager.h"
-#include "components/translate/core/common/translate_util.h"
 #include "components/ukm/content/source_url_recorder.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_controller.h"
@@ -30,14 +29,12 @@
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/referrer.h"
 #include "content/public/common/web_preferences.h"
 #include "net/http/http_status_code.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
-#include "services/network/public/mojom/network_context.mojom.h"
 #include "url/gurl.h"
 
 namespace translate {
@@ -125,29 +122,6 @@
     observer.OnIsPageTranslatedChanged(web_contents);
 }
 
-network::mojom::URLLoaderFactoryPtr
-ContentTranslateDriver::CreateURLLoaderFactory() {
-  // Find the renderer process that will need to use the URLLoaderFactory.
-  // Currently translate requests are only sent to the main frame process.
-  content::RenderProcessHost* process =
-      web_contents()->GetMainFrame()->GetProcess();
-
-  // Create a new URLLoaderFactory, locking the initiator origin to the one
-  // returned by GetTranslateSecurityOrigin.
-  network::mojom::URLLoaderFactoryPtr factory;
-  url::Origin origin = url::Origin::Create(GetTranslateSecurityOrigin());
-
-  // TODO(crbug.com/940068): Since this factory will be removed, sending an
-  // empty network isolation key for now.
-  content::WebPreferences preferences =
-      web_contents()->GetRenderViewHost()->GetWebkitPreferences();
-  process->CreateURLLoaderFactory(
-      origin, network::mojom::CrossOriginEmbedderPolicy::kNone, &preferences,
-      net::NetworkIsolationKey(), mojo::NullRemote(),
-      mojo::MakeRequest(&factory));
-  return factory;
-}
-
 void ContentTranslateDriver::TranslatePage(int page_seq_no,
                                            const std::string& translate_script,
                                            const std::string& source_lang,
@@ -157,7 +131,7 @@
     return;  // This page has navigated away.
 
   it->second->Translate(
-      translate_script, CreateURLLoaderFactory(), source_lang, target_lang,
+      translate_script, source_lang, target_lang,
       base::BindOnce(&ContentTranslateDriver::OnPageTranslated,
                      base::Unretained(this)));
 }
diff --git a/components/translate/content/browser/content_translate_driver.h b/components/translate/content/browser/content_translate_driver.h
index 8ac4d10..9ee7e1d 100644
--- a/components/translate/content/browser/content_translate_driver.h
+++ b/components/translate/content/browser/content_translate_driver.h
@@ -20,7 +20,6 @@
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
-#include "services/network/public/mojom/url_loader_factory.mojom.h"
 
 namespace content {
 class NavigationController;
@@ -125,13 +124,6 @@
  private:
   void OnPageAway(int page_seq_no);
 
-  // Creates a URLLoaderFactory that may be used by the translate scripts that
-  // get injected into isolated worlds within the page to be translated.  Such
-  // scripts (or rather, their isolated worlds) are associated with a
-  // translate-specific origin like https://translate.googleapis.com and use
-  // this origin as |request_initiator| of http requests.
-  network::mojom::URLLoaderFactoryPtr CreateURLLoaderFactory();
-
   // The navigation controller of the tab we are associated with.
   content::NavigationController* navigation_controller_;
 
diff --git a/components/translate/content/common/BUILD.gn b/components/translate/content/common/BUILD.gn
index ae52137..a5b6a678 100644
--- a/components/translate/content/common/BUILD.gn
+++ b/components/translate/content/common/BUILD.gn
@@ -11,7 +11,6 @@
 
   public_deps = [
     "//mojo/public/mojom/base",
-    "//services/network/public/mojom:mojom",
     "//url/mojom:url_mojom_gurl",
   ]
 }
diff --git a/components/translate/content/common/translate.mojom b/components/translate/content/common/translate.mojom
index bc4a9f0..fc018ac 100644
--- a/components/translate/content/common/translate.mojom
+++ b/components/translate/content/common/translate.mojom
@@ -6,7 +6,6 @@
 
 import "mojo/public/mojom/base/time.mojom";
 import "mojo/public/mojom/base/string16.mojom";
-import "services/network/public/mojom/url_loader_factory.mojom";
 import "url/mojom/url.mojom";
 
 enum TranslateError {
@@ -40,12 +39,6 @@
   // Requests that the page be translated from |source_lang| to
   // |target_lang|.
   //
-  // |loader_factory_for_translate_script| should provide a factory that the
-  // translation scripts can use for making fetch requests associated with the
-  // "translate" origin (the default factory's |request_initiator_site_lock| is
-  // not compatible with |request_initiator| of fetch requests initiated by the
-  // "translate" origin).
-  //
   // If a Translate request is already in progress with a matching
   // |target_lang|, this request will respond with |cancelled| set
   // to |true|.
@@ -56,10 +49,7 @@
   //
   // If |cancelled| is |true| all other response values should be
   // ignored.
-  Translate(string translate_script,
-            network.mojom.URLLoaderFactory loader_factory_for_translate_script,
-            string source_lang,
-            string target_lang)
+  Translate(string translate_script, string source_lang, string target_lang)
       => (bool cancelled, string original_lang, string translated_lang,
           TranslateError error);
 
diff --git a/components/translate/content/renderer/BUILD.gn b/components/translate/content/renderer/BUILD.gn
index 72a8873..d04d8d6 100644
--- a/components/translate/content/renderer/BUILD.gn
+++ b/components/translate/content/renderer/BUILD.gn
@@ -15,6 +15,8 @@
     "//components/translate/content/common",
     "//components/translate/core/common",
     "//components/translate/core/language_detection",
+    "//content/public/common",
+    "//content/public/renderer",
     "//services/service_manager/public/cpp",
     "//third_party/blink/public:blink",
     "//url",
@@ -22,8 +24,6 @@
   ]
 
   public_deps = [
-    "//content/public/common",
-    "//content/public/renderer",
     "//third_party/blink/public:blink_headers",
   ]
 }
diff --git a/components/translate/content/renderer/translate_helper.cc b/components/translate/content/renderer/translate_helper.cc
index 944bdc8d..9fda4a4 100644
--- a/components/translate/content/renderer/translate_helper.cc
+++ b/components/translate/content/renderer/translate_helper.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/feature_list.h"
 #include "base/json/string_escape.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -26,7 +25,6 @@
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
-#include "third_party/blink/public/common/loader/url_loader_factory_bundle.h"
 #include "third_party/blink/public/platform/web_isolated_world_info.h"
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_language_detection_details.h"
@@ -281,16 +279,9 @@
 // mojom::Page implementations.
 void TranslateHelper::Translate(
     const std::string& translate_script,
-    network::mojom::URLLoaderFactoryPtr loader_factory_for_translate_script,
     const std::string& source_lang,
     const std::string& target_lang,
     TranslateCallback callback) {
-  url::Origin translate_origin =
-      url::Origin::Create(GetTranslateSecurityOrigin());
-
-  render_frame()->MarkInitiatorAsRequiringSeparateURLLoaderFactory(
-      translate_origin, std::move(loader_factory_for_translate_script));
-
   WebLocalFrame* main_frame = render_frame()->GetWebFrame();
   if (!main_frame) {
     // Cancelled.
@@ -327,7 +318,8 @@
   // Set up v8 isolated world with proper content-security-policy and
   // security-origin.
   blink::WebIsolatedWorldInfo info;
-  info.security_origin = WebSecurityOrigin::Create(translate_origin.GetURL());
+  info.security_origin =
+      WebSecurityOrigin::Create(GetTranslateSecurityOrigin());
   info.content_security_policy = WebString::FromUTF8(kContentSecurityPolicy);
   main_frame->SetIsolatedWorldInfo(world_id_, info);
 
diff --git a/components/translate/content/renderer/translate_helper.h b/components/translate/content/renderer/translate_helper.h
index 7ccd4e2..96092fc0 100644
--- a/components/translate/content/renderer/translate_helper.h
+++ b/components/translate/content/renderer/translate_helper.h
@@ -18,7 +18,6 @@
 #include "content/public/renderer/render_frame_observer.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "url/gurl.h"
 
 namespace blink {
@@ -46,12 +45,10 @@
   void PrepareForUrl(const GURL& url);
 
   // mojom::Page implementation.
-  void Translate(
-      const std::string& translate_script,
-      network::mojom::URLLoaderFactoryPtr loader_factory_for_translate_script,
-      const std::string& source_lang,
-      const std::string& target_lang,
-      TranslateCallback callback) override;
+  void Translate(const std::string& translate_script,
+                 const std::string& source_lang,
+                 const std::string& target_lang,
+                 TranslateCallback callback) override;
   void RevertTranslation() override;
 
  protected:
diff --git a/components/typemaps.gni b/components/typemaps.gni
index 201c895..879e779 100644
--- a/components/typemaps.gni
+++ b/components/typemaps.gni
@@ -10,7 +10,6 @@
   "//components/content_settings/core/common/content_settings.typemap",
   "//components/nacl/common/nacl.typemap",
   "//components/password_manager/content/common/credential_manager.typemap",
-  "//components/services/leveldb/leveldb.typemap",
   "//components/spellcheck/common/spellcheck.typemap",
   "//components/translate/content/common/translate.typemap",
 ]
diff --git a/components/update_client/protocol_serializer_json_unittest.cc b/components/update_client/protocol_serializer_json_unittest.cc
index 4cf2666f..eb9fca0 100644
--- a/components/update_client/protocol_serializer_json_unittest.cc
+++ b/components/update_client/protocol_serializer_json_unittest.cc
@@ -70,7 +70,7 @@
       R"("version":"2.0"}],"arch":"\w+","dedup":"cr","dlpref":"cacheable",)"
       R"("extra":"params","hw":{"physmemory":\d+},"lang":"lang",)"
       R"("nacl_arch":"[-\w]+","os":{"arch":"[_,-.\w]+","platform":"OS",)"
-      R"(("sp":"[\s\w]+",)?"version":"[-.\w]+"},"prodchannel":"channel",)"
+      R"(("sp":"[\s\w]+",)?"version":"[+-.\w]+"},"prodchannel":"channel",)"
       R"("prodversion":"1.0","protocol":"3.1","requestid":"{[-\w]{36}}",)"
       R"("sessionid":"{[-\w]{36}}","updaterchannel":"channel",)"
       R"("updaterversion":"1.0"(,"wow64":true)?}})";
@@ -114,7 +114,7 @@
       R"("dlpref":"cacheable","domainjoined":true,"extra":"params",)"
       R"("hw":{"physmemory":\d+},"lang":"lang","nacl_arch":"[-\w]+",)"
       R"("os":{"arch":"[,-.\w]+","platform":"OS",("sp":"[\s\w]+",)?)"
-      R"("version":"[-.\w]+"},"prodchannel":"channel","prodversion":"1.0",)"
+      R"("version":"[+-.\w]+"},"prodchannel":"channel","prodversion":"1.0",)"
       R"("protocol":"3.1","requestid":"{[-\w]{36}}","sessionid":"{[-\w]{36}}",)"
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
       R"("updater":{"autoupdatecheckenabled":false,"ismachine":true,)"
diff --git a/components/url_formatter/spoof_checks/top_domains/BUILD.gn b/components/url_formatter/spoof_checks/top_domains/BUILD.gn
index e5ac5ee9..fe5aca7 100644
--- a/components/url_formatter/spoof_checks/top_domains/BUILD.gn
+++ b/components/url_formatter/spoof_checks/top_domains/BUILD.gn
@@ -69,9 +69,9 @@
          rebase_path(outputs, root_build_dir) + [ "--for_testing" ]
 }
 
-executable("make_top_domain_list_for_edit_distance") {
+executable("make_top_domain_list_variables") {
   sources = [
-    "make_top_domain_list_for_edit_distance.cc",
+    "make_top_domain_list_variables.cc",
   ]
   deps = [
     ":common",
@@ -108,8 +108,8 @@
 
 # TODO(crbug/915921): Combine this and the previous one into a
 # compiled_action_foreach target.
-compiled_action("generate_top_domains_for_edit_distance") {
-  tool = ":make_top_domain_list_for_edit_distance"
+compiled_action("generate_top_domain_list_variables_file") {
+  tool = ":make_top_domain_list_variables"
 
   # Inputs in order expected by the command line of the tool.
   inputs = [
@@ -124,7 +124,7 @@
 
 # top500_domains and top500_domains_header are intentionally separated to remove
 # serialized build dependency from some targets to
-# generate_top_domains_for_edit_distance action target.
+# generate_top_domain_list_variables action target.
 source_set("top500_domains") {
   # This empty public is intentional to remove unnecessary build dependency.
   public = []
@@ -134,7 +134,7 @@
   ]
 
   deps = [
-    ":generate_top_domains_for_edit_distance",
+    ":generate_top_domain_list_variables_file",
     ":top500_domains_header",
   ]
 }
diff --git a/components/url_formatter/spoof_checks/top_domains/README b/components/url_formatter/spoof_checks/top_domains/README.md
similarity index 60%
rename from components/url_formatter/spoof_checks/top_domains/README
rename to components/url_formatter/spoof_checks/top_domains/README.md
index f883e3b..ca2c41b 100644
--- a/components/url_formatter/spoof_checks/top_domains/README
+++ b/components/url_formatter/spoof_checks/top_domains/README.md
@@ -1,10 +1,12 @@
-* domains.list
+### Top Domains Utilities
+
+* `domains.list`
 
   A top domain list, one per line. Used as an input to
   make_top_domain_skeletons. See http://go/chrome-top-domains-update for update
   instructions.
 
-* domains.skeletons
+* `domains.skeletons`
 
   The checked-in output of make_top_domain_skeletons.  Processed during the
   build to generate domains-trie-inc.cc, which is used by
@@ -14,10 +16,19 @@
   $ ninja -C $build_outdir make_top_domain_skeletons
   $ $build_outdir/make_top_domain_skeletons
 
-* test_domains.list
+* `test_domains.list`
+
   A list of domains to use in IDNToUnicode test instead of the actual
   top domain list. Manually edited to match what's in IDNToUnicode test.
 
-* test_domains.skeletons
+* `test_domains.skeletons`
+
   Generated output of test_domains.list along with domains.skeletons
   by make_top_domain_skeletons.
+
+* `top_domain_list_variable_builder.cc` / `top500_domains.h`
+
+  `top_domain_list_variable_builder.cc` is run at compile time to generate information about the top 500 domains
+  (currently, skeletons and keywords are created from these domains). This
+  information is then embedded directly into the chrome binary, and can be
+  accessed via the variables in the top500_domains namespace.
diff --git a/components/url_formatter/spoof_checks/top_domains/make_top_domain_list_for_edit_distance.cc b/components/url_formatter/spoof_checks/top_domains/make_top_domain_list_variables.cc
similarity index 60%
rename from components/url_formatter/spoof_checks/top_domains/make_top_domain_list_for_edit_distance.cc
rename to components/url_formatter/spoof_checks/top_domains/make_top_domain_list_variables.cc
index 866fc567..1207cee 100644
--- a/components/url_formatter/spoof_checks/top_domains/make_top_domain_list_for_edit_distance.cc
+++ b/components/url_formatter/spoof_checks/top_domains/make_top_domain_list_variables.cc
@@ -2,9 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This binary generates an array of top domains suitable for edit distance
-// matching. The input is the list of (skeleton, domain) pairs. The output is
-// written as a C array of the domains.
+// This binary generates two C arrays of useful information related to top
+// domains, which we embed directly into
+// the final Chrome binary.  The input is a list of the top domains. The first
+// output is named kTop500EditDistanceSkeletons,
+// containing the skeletons of the top 500 domains suitable for use in the edit
+// distance heuristic. The second output is named kTop500Keywords,
+// containg the top 500 keywords suitable for use with the keyword matching
+// heuristic (for instance, www.google.com -> google). Both outputs are written
+// to the same file, which will be formatted as c++ source file with valid
+// syntax.
+
+// The C-strings in both of the output arrays are guaranteed to be in
+// lexicographically sorted order.
+
+// IMPORTANT: This binary asserts that there are at least enough sites in the
+// input file to generate 500 skeletons and 500 keywords.
 
 #include <iostream>
 #include <string>
@@ -96,30 +109,68 @@
     return 1;
   }
 
-  size_t count = 0;
-  std::string output =
-      R"(#include "components/url_formatter/spoof_checks/top_domains/top500_domains.h"
-namespace top500_domains {
-const char* const kTop500[500] = {
-)";
+  std::set<std::string> skeletons;
+  std::set<std::string> keywords;
+
   for (std::string line : lines) {
+    if (skeletons.size() >= kTopN && keywords.size() >= kTopN) {
+      break;
+    }
     base::TrimWhitespaceASCII(line, base::TRIM_ALL, &line);
     if (line.empty() || line[0] == '#') {
       continue;
     }
-    if (count >= kTopN)
-      break;
-    if (!url_formatter::top_domains::IsEditDistanceCandidate(line)) {
-      continue;
+
+    if (skeletons.size() < kTopN &&
+        url_formatter::top_domains::IsEditDistanceCandidate(line)) {
+      const std::string skeleton = GetSkeleton(line, spoof_checker.get());
+      if (skeletons.find(skeleton) == skeletons.end()) {
+        skeletons.insert(skeleton);
+      }
     }
-    count++;
-    const std::string skeleton = GetSkeleton(line, spoof_checker.get());
-    output += "\"" + skeleton + "\",\n";
+
+    if (keywords.size() < kTopN) {
+      std::string keyword;
+      base::TrimString(
+          url_formatter::top_domains::HostnameWithoutRegistry(line), ".",
+          &keyword);
+      CHECK(keyword.find('.') == std::string::npos);
+      if (keywords.find(keyword) == keywords.end()) {
+        keywords.insert(keyword);
+      }
+    }
+  }
+
+  CHECK_EQ(skeletons.size(), kTopN);
+  CHECK_EQ(keywords.size(), kTopN);
+
+  std::vector<std::string> sorted_skeletons(skeletons.begin(), skeletons.end());
+  std::sort(sorted_skeletons.begin(), sorted_skeletons.end());
+
+  std::vector<std::string> sorted_keywords(keywords.begin(), keywords.end());
+  std::sort(sorted_keywords.begin(), sorted_keywords.end());
+
+  std::string output =
+      R"(#include "components/url_formatter/spoof_checks/top_domains/top500_domains.h"
+namespace top500_domains {
+const char* const kTop500EditDistanceSkeletons[500] = {
+)";
+
+  for (const std::string& skeleton : sorted_skeletons) {
+    output += ("\"" + skeleton + "\"");
+    output += ",\n";
   }
   output += R"(};
-}  // namespace top500_domains
+const char* const kTop500Keywords[500] = {
 )";
 
+  for (const std::string& keyword : sorted_keywords) {
+    output += ("\"" + keyword + "\"");
+    output += ",\n";
+  }
+  output += R"(};
+}  // namespace top500_domains)";
+
   base::FilePath output_path = base::FilePath::FromUTF8Unsafe(argv[2]);
   if (base::WriteFile(output_path, output.c_str(),
                       static_cast<uint32_t>(output.size())) <= 0) {
diff --git a/components/url_formatter/spoof_checks/top_domains/top500_domains.h b/components/url_formatter/spoof_checks/top_domains/top500_domains.h
index 16b211c..a4d9f845 100644
--- a/components/url_formatter/spoof_checks/top_domains/top500_domains.h
+++ b/components/url_formatter/spoof_checks/top_domains/top500_domains.h
@@ -6,7 +6,9 @@
 
 namespace top500_domains {
 
-extern const char* const kTop500[500];
+extern const char* const kTop500EditDistanceSkeletons[500];
+
+extern const char* const kTop500Keywords[500];
 
 }  // namespace top500_domains
 
diff --git a/components/url_formatter/spoof_checks/top_domains/top_domain_util.cc b/components/url_formatter/spoof_checks/top_domains/top_domain_util.cc
index bb9bead..763eaad 100644
--- a/components/url_formatter/spoof_checks/top_domains/top_domain_util.cc
+++ b/components/url_formatter/spoof_checks/top_domains/top_domain_util.cc
@@ -17,6 +17,11 @@
 
 }  // namespace
 
+bool IsEditDistanceCandidate(const std::string& hostname) {
+  return !hostname.empty() &&
+         HostnameWithoutRegistry(hostname).size() >= kMinLengthForEditDistance;
+}
+
 std::string HostnameWithoutRegistry(const std::string& hostname) {
   DCHECK(!hostname.empty());
   const size_t registry_size =
@@ -27,11 +32,6 @@
   return hostname.substr(0, hostname.size() - registry_size);
 }
 
-bool IsEditDistanceCandidate(const std::string& hostname) {
-  return !hostname.empty() &&
-         HostnameWithoutRegistry(hostname).size() >= kMinLengthForEditDistance;
-}
-
 }  // namespace top_domains
 
 }  // namespace url_formatter
diff --git a/components/viz/test/test_context_support.cc b/components/viz/test/test_context_support.cc
index 173cc4d..f2cd6b7 100644
--- a/components/viz/test/test_context_support.cc
+++ b/components/viz/test/test_context_support.cc
@@ -138,7 +138,7 @@
   return false;
 }
 bool TestContextSupport::CanDecodeWithHardwareAcceleration(
-    base::span<const uint8_t> encoded_data) const {
+    const cc::ImageHeaderMetadata* image_metadata) const {
   return false;
 }
 
diff --git a/components/viz/test/test_context_support.h b/components/viz/test/test_context_support.h
index 8bc6fe1..1bb393dc 100644
--- a/components/viz/test/test_context_support.h
+++ b/components/viz/test/test_context_support.h
@@ -80,7 +80,7 @@
   bool IsJpegDecodeAccelerationSupported() const override;
   bool IsWebPDecodeAccelerationSupported() const override;
   bool CanDecodeWithHardwareAcceleration(
-      base::span<const uint8_t> encoded_data) const override;
+      const cc::ImageHeaderMetadata* image_metadata) const override;
   bool HasGrContextSupport() const override;
   void SetGrContext(GrContext* gr) override;
   void WillCallGLFromSkia() override;
diff --git a/components/web_cache/browser/web_cache_manager.cc b/components/web_cache/browser/web_cache_manager.cc
index 75f9372..33c69da 100644
--- a/components/web_cache/browser/web_cache_manager.cc
+++ b/components/web_cache/browser/web_cache_manager.cc
@@ -18,7 +18,6 @@
 #include "base/time/time.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
-#include "content/public/browser/render_process_host.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 
 using base::Time;
diff --git a/components/web_cache/browser/web_cache_manager.h b/components/web_cache/browser/web_cache_manager.h
index ec5144a..46f548f 100644
--- a/components/web_cache/browser/web_cache_manager.h
+++ b/components/web_cache/browser/web_cache_manager.h
@@ -22,6 +22,7 @@
 #include "base/scoped_observer.h"
 #include "base/time/time.h"
 #include "components/web_cache/public/mojom/web_cache.mojom.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_process_host_creation_observer.h"
 #include "content/public/browser/render_process_host_observer.h"
 #include "mojo/public/cpp/bindings/remote.h"
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index f725b94..c53d301 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -52,10 +52,10 @@
 #include "content/browser/scheduler/browser_task_executor.h"
 #include "content/browser/startup_data_impl.h"
 #include "content/browser/startup_helper.h"
+#include "content/browser/tracing/memory_instrumentation_util.h"
 #include "content/common/content_constants_internal.h"
 #include "content/common/url_schemes.h"
 #include "content/public/app/content_main_delegate.h"
-#include "content/public/browser/resource_coordinator_service.h"
 #include "content/public/browser/system_connector.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_descriptor_keys.h"
@@ -70,8 +70,6 @@
 #include "media/media_buildflags.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "services/network/public/cpp/features.h"
-#include "services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h"
-#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
 #include "services/service_manager/embedder/switches.h"
 #include "services/service_manager/sandbox/sandbox_type.h"
 #include "services/service_manager/sandbox/switches.h"
@@ -417,23 +415,6 @@
 
 #endif  // OS_LINUX
 
-#if !defined(CHROME_MULTIPLE_DLL_CHILD)
-void InitializeBrowserClientProcessImpl() {
-  // Registers the browser process as a memory-instrumentation client, so
-  // that data for the browser process will be available in memory dumps.
-  mojo::PendingRemote<memory_instrumentation::mojom::Coordinator> coordinator;
-  mojo::PendingRemote<memory_instrumentation::mojom::ClientProcess> process;
-  auto process_receiver = process.InitWithNewPipeAndPassReceiver();
-  GetMemoryInstrumentationCoordinatorController()->RegisterClientProcess(
-      coordinator.InitWithNewPipeAndPassReceiver(), std::move(process),
-      memory_instrumentation::mojom::ProcessType::BROWSER,
-      base::GetCurrentProcId(), /*service_name=*/base::nullopt);
-  memory_instrumentation::ClientProcessImpl::CreateInstance(
-      std::move(process_receiver), std::move(coordinator),
-      /*is_browser_process=*/true);
-}
-#endif  // !defined(CHROME_MULTIPLE_DLL_CHILD)
-
 }  // namespace
 
 class ContentClientInitializer {
@@ -975,7 +956,7 @@
     download::SetIOTaskRunner(
         service_manager_environment_->ipc_thread()->task_runner());
 
-    InitializeBrowserClientProcessImpl();
+    InitializeBrowserMemoryInstrumentationClient();
 
 #if defined(OS_ANDROID)
     if (start_service_manager_only) {
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 5a30d88c..3ddb223 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1816,6 +1816,8 @@
     "tracing/background_tracing_rule.h",
     "tracing/file_tracing_provider_impl.cc",
     "tracing/file_tracing_provider_impl.h",
+    "tracing/memory_instrumentation_util.cc",
+    "tracing/memory_instrumentation_util.h",
     "tracing/perfetto_file_tracer.cc",
     "tracing/perfetto_file_tracer.h",
     "tracing/tracing_controller_impl.cc",
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 46409fa..f5db6d0 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -17,6 +17,7 @@
   "+components/services/leveldb",
   "+components/services/quarantine/test_support.h",
   "+components/services/quarantine/quarantine.h",
+  "+components/services/storage",
   "+components/session_manager/core",
   "+components/leveldb_proto/public",
   "+components/link_header_util",
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index b5c09e9..26b3e43 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -2731,4 +2731,26 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Encoding) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const GURL url_a(embedded_test_server()->GetURL(
+      "a.com", "/back_forward_cache/charset_windows-1250.html"));
+  const GURL url_b(embedded_test_server()->GetURL(
+      "b.com", "/back_forward_cache/charset_utf-8.html"));
+  const url::Origin origin_a = url::Origin::Create(url_a);
+  const url::Origin origin_b = url::Origin::Create(url_b);
+
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  EXPECT_EQ(web_contents()->GetEncoding(), "windows-1250");
+
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  EXPECT_TRUE(rfh_a->is_in_back_forward_cache());
+  EXPECT_EQ(web_contents()->GetEncoding(), "UTF-8");
+
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  EXPECT_EQ(web_contents()->GetEncoding(), "windows-1250");
+}
+
 }  // namespace content
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 6910f5a..e9c608d 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -1859,23 +1859,23 @@
   op_scheduler_.ScheduleOperation(
       id, CacheStorageSchedulerMode::kExclusive,
       CacheStorageSchedulerOp::kBackgroundSync,
-      base::BindOnce(
-          &BackgroundSyncManager::FireReadyEventsImpl,
-          weak_ptr_factory_.GetWeakPtr(), sync_type, reschedule,
-          op_scheduler_.WrapCallbackToRunNext(id, std::move(callback)),
-          std::move(keepalive)));
+      base::BindOnce(&BackgroundSyncManager::FireReadyEventsImpl,
+                     weak_ptr_factory_.GetWeakPtr(), sync_type, reschedule, id,
+                     std::move(callback), std::move(keepalive)));
 }
 
 void BackgroundSyncManager::FireReadyEventsImpl(
     blink::mojom::BackgroundSyncType sync_type,
     bool reschedule,
+    int scheduler_id,
     base::OnceClosure callback,
     std::unique_ptr<BackgroundSyncEventKeepAlive> keepalive) {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
 
   if (disabled_) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  std::move(callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        op_scheduler_.WrapCallbackToRunNext(scheduler_id, std::move(callback)));
     return;
   }
 
@@ -1917,27 +1917,46 @@
     // called from a wakeup task.
     if (reschedule)
       ScheduleOrCancelDelayedProcessing(sync_type);
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  std::move(callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        op_scheduler_.WrapCallbackToRunNext(scheduler_id, std::move(callback)));
     return;
   }
 
   base::TimeTicks start_time = base::TimeTicks::Now();
 
-  // Fire the sync event of the ready registrations and run |callback| once
-  // they're all done.
+  // If we've been called from a wake up task, potentially keep the browser
+  // awake till all events have completed. If not, we only do so until all
+  // events have been fired.
+  // To allow the |op_scheduler_| to process other tasks after sync events
+  // have been fired, mark this task complete after firing events.
+  base::OnceClosure events_fired_callback, events_completed_callback;
+  bool keep_browser_awake_till_events_complete =
+      !reschedule && parameters_->keep_browser_awake_till_events_complete;
+  if (keep_browser_awake_till_events_complete) {
+    events_fired_callback = MakeEmptyCompletion(scheduler_id);
+    events_completed_callback = std::move(callback);
+  } else {
+    events_fired_callback =
+        op_scheduler_.WrapCallbackToRunNext(scheduler_id, std::move(callback));
+    events_completed_callback = base::DoNothing::Once();
+  }
+
+  // Fire the sync event of the ready registrations and run
+  // |events_fired_closure| once they're all done.
   base::RepeatingClosure events_fired_barrier_closure = base::BarrierClosure(
       to_fire.size(),
       base::BindOnce(&BackgroundSyncManager::FireReadyEventsAllEventsFiring,
                      weak_ptr_factory_.GetWeakPtr(), sync_type, reschedule,
-                     std::move(callback)));
+                     std::move(events_fired_callback)));
 
   // Record the total time taken after all events have run to completion.
   base::RepeatingClosure events_completed_barrier_closure =
       base::BarrierClosure(
           to_fire.size(),
-          base::BindOnce(&OnAllSyncEventsCompleted, sync_type, start_time,
-                         !reschedule, to_fire.size()));
+          base::BindOnce(&BackgroundSyncManager::OnAllSyncEventsCompleted,
+                         sync_type, start_time, !reschedule, to_fire.size(),
+                         std::move(events_completed_callback)));
 
   for (auto& registration_info : to_fire) {
     const BackgroundSyncRegistration* registration =
@@ -2036,6 +2055,7 @@
 
   if (reschedule)
     ScheduleOrCancelDelayedProcessing(sync_type);
+
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
 }
 
@@ -2277,11 +2297,13 @@
     BackgroundSyncType sync_type,
     const base::TimeTicks& start_time,
     bool from_wakeup_task,
-    int number_of_batched_sync_events) {
+    int number_of_batched_sync_events,
+    base::OnceClosure callback) {
   // Record the combined time taken by all sync events.
   BackgroundSyncMetrics::RecordBatchSyncEventComplete(
       sync_type, base::TimeTicks::Now() - start_time, from_wakeup_task,
       number_of_batched_sync_events);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
 }
 
 void BackgroundSyncManager::OnRegistrationDeletedImpl(
diff --git a/content/browser/background_sync/background_sync_manager.h b/content/browser/background_sync/background_sync_manager.h
index c795451..a37efa8 100644
--- a/content/browser/background_sync/background_sync_manager.h
+++ b/content/browser/background_sync/background_sync_manager.h
@@ -147,7 +147,7 @@
   // Scans the list of available events and fires those of type |sync_type| that
   // are ready to fire. For those that can't yet be fired, wakeup alarms are
   // set. Once all of this is done, invokes |callback|.
-  void FireReadyEvents(
+  virtual void FireReadyEvents(
       blink::mojom::BackgroundSyncType sync_type,
       bool reschedule,
       base::OnceClosure callback,
@@ -339,9 +339,18 @@
   void ScheduleDelayedProcessingOfRegistrations(
       blink::mojom::BackgroundSyncType sync_type);
 
+  // Fires ready events for |sync_type|.
+  // |reschedule| is true when it's ok to schedule background processing from
+  // this method, false otherwise.
+  // |scheduler_id| is an id unique to the |op_scheduler_| task. It's passed to
+  // correctly mark this operation as finished with the |op_scheduler_| and run
+  // the next operation scheduled.
+  // |keepalive| is used to keep the browser alive until the first attempt to
+  // fire a sync event has been made.
   void FireReadyEventsImpl(
       blink::mojom::BackgroundSyncType sync_type,
       bool reschedule,
+      int scheduler_id,
       base::OnceClosure callback,
       std::unique_ptr<BackgroundSyncEventKeepAlive> keepalive);
 
@@ -386,7 +395,8 @@
       blink::mojom::BackgroundSyncType sync_type,
       const base::TimeTicks& start_time,
       bool from_wakeup_task,
-      int number_of_batched_sync_events);
+      int number_of_batched_sync_events,
+      base::OnceClosure callback);
 
   // OnRegistrationDeleted callbacks
   void OnRegistrationDeletedImpl(int64_t sw_registration_id,
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index d9bcf72..5f69942 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -672,6 +672,15 @@
     SetupBackgroundSyncManager();
   }
 
+  void SetKeepBrowserAwakeTillEventsCompleteAndRestartManager(
+      bool keep_browser_awake_till_events_complete) {
+    BackgroundSyncParameters* parameters =
+        GetController()->background_sync_parameters();
+    parameters->keep_browser_awake_till_events_complete =
+        keep_browser_awake_till_events_complete;
+    SetupBackgroundSyncManager();
+  }
+
   void FireReadyEvents() { test_background_sync_manager()->OnNetworkChanged(); }
 
   bool AreOptionConditionsMet() {
@@ -1384,6 +1393,33 @@
   EXPECT_FALSE(GetRegistration(sync_options_1_));
 }
 
+TEST_F(BackgroundSyncManagerTest, RunCallbackAfterEventsComplete) {
+  SetKeepBrowserAwakeTillEventsCompleteAndRestartManager(
+      /* keep_browser_awake_till_events_complete= */ true);
+  InitDelayedSyncEventTest();
+
+  // This ensures other invocations of FireReadyEvents won't complete the
+  // registration.
+  test_background_sync_manager()->SuspendFiringEvents();
+
+  EXPECT_TRUE(Register(sync_options_1_));
+
+  bool callback_called = false;
+  test_background_sync_manager()->ResumeFiringEvents();
+  test_background_sync_manager()->FireReadyEvents(
+      blink::mojom::BackgroundSyncType::ONE_SHOT,
+      /* reschedule= */ false,
+      base::BindOnce([](bool* callback_called) { *callback_called = true; },
+                     &callback_called));
+
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_FALSE(callback_called);
+  std::move(sync_fired_callback_).Run(blink::ServiceWorkerStatusCode::kOk);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(callback_called);
+}
+
 TEST_F(BackgroundSyncManagerTest, ReregisterMidSyncFirstAttemptSucceeds) {
   InitDelayedSyncEventTest();
   RegisterAndVerifySyncEventDelayed(sync_options_1_);
diff --git a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
index 6726ef3..7133a03 100644
--- a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
+++ b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
@@ -235,10 +235,11 @@
       discovery_session_timer_(
           FROM_HERE,
           base::TimeDelta::FromSeconds(scan_duration_),
-          base::Bind(&BluetoothDeviceChooserController::StopDeviceDiscovery,
-                     // base::Timer guarantees it won't call back after its
-                     // destructor starts.
-                     base::Unretained(this))) {
+          base::BindRepeating(
+              &BluetoothDeviceChooserController::StopDeviceDiscovery,
+              // base::Timer guarantees it won't call back after its
+              // destructor starts.
+              base::Unretained(this))) {
   CHECK(adapter_);
 }
 
@@ -313,9 +314,9 @@
     return;
   }
 
-  BluetoothChooser::EventHandler chooser_event_handler =
-      base::Bind(&BluetoothDeviceChooserController::OnBluetoothChooserEvent,
-                 base::Unretained(this));
+  BluetoothChooser::EventHandler chooser_event_handler = base::BindRepeating(
+      &BluetoothDeviceChooserController::OnBluetoothChooserEvent,
+      base::Unretained(this));
 
   if (WebContentsDelegate* delegate = web_contents_->GetDelegate()) {
     chooser_ = delegate->RunBluetoothChooser(render_frame_host_,
diff --git a/content/browser/bluetooth/bluetooth_device_scanning_prompt_controller.cc b/content/browser/bluetooth/bluetooth_device_scanning_prompt_controller.cc
index 276f52f..39fe69e 100644
--- a/content/browser/bluetooth/bluetooth_device_scanning_prompt_controller.cc
+++ b/content/browser/bluetooth/bluetooth_device_scanning_prompt_controller.cc
@@ -28,9 +28,10 @@
 }
 
 void BluetoothDeviceScanningPromptController::ShowPermissionPrompt() {
-  BluetoothScanningPrompt::EventHandler prompt_event_handler = base::Bind(
-      &BluetoothDeviceScanningPromptController::OnBluetoothScanningPromptEvent,
-      base::Unretained(this));
+  BluetoothScanningPrompt::EventHandler prompt_event_handler =
+      base::BindRepeating(&BluetoothDeviceScanningPromptController::
+                              OnBluetoothScanningPromptEvent,
+                          base::Unretained(this));
   WebContentsDelegate* delegate =
       WebContents::FromRenderFrameHost(render_frame_host_)->GetDelegate();
   if (delegate) {
diff --git a/content/browser/broadcast_channel/broadcast_channel_provider.cc b/content/browser/broadcast_channel/broadcast_channel_provider.cc
index 34a5df131..d9caeaa 100644
--- a/content/browser/broadcast_channel/broadcast_channel_provider.cc
+++ b/content/browser/broadcast_channel/broadcast_channel_provider.cc
@@ -34,7 +34,8 @@
   const url::Origin& origin() const { return origin_; }
   const std::string& name() const { return name_; }
 
-  void set_connection_error_handler(const base::Closure& error_handler) {
+  void set_connection_error_handler(
+      const base::RepeatingClosure& error_handler) {
     receiver_.set_disconnect_handler(error_handler);
     client_.set_disconnect_handler(error_handler);
   }
@@ -98,8 +99,8 @@
   std::unique_ptr<Connection> c(new Connection(origin, name, std::move(client),
                                                std::move(connection), this));
   c->set_connection_error_handler(
-      base::Bind(&BroadcastChannelProvider::UnregisterConnection,
-                 base::Unretained(this), c.get()));
+      base::BindRepeating(&BroadcastChannelProvider::UnregisterConnection,
+                          base::Unretained(this), c.get()));
   connections_[origin].insert(std::make_pair(name, std::move(c)));
 }
 
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc
index ec04b2f..597dd7f 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -435,17 +435,14 @@
                      std::move(receiver)));
 }
 
-void DOMStorageContextWrapper::SetLocalStorageDatabaseFactoryForTesting(
-    base::RepeatingCallback<std::unique_ptr<leveldb::mojom::LevelDBDatabase>()>
-        factory) {
-  // base::Unretained is safe here, because the mojo_state_ won't be deleted
-  // until a ShutdownAndDelete task has been ran on the mojo_task_runner_, and
-  // as soon as that task is posted, mojo_state_ is set to null, preventing
-  // further tasks from being queued.
+void DOMStorageContextWrapper::SetLocalStorageDatabaseOpenCallbackForTesting(
+    LocalStorageDatabaseOpenCallback callback) {
   mojo_task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(&LocalStorageContextMojo::SetDatabaseFactoryForTesting,
-                     base::Unretained(mojo_state_), std::move(factory)));
+      base::BindOnce(
+          &LocalStorageContextMojo::SetDatabaseOpenCallbackForTesting,
+          base::Unretained(mojo_state_),
+          base::BindOnce(std::move(callback), mojo_state_)));
 }
 
 scoped_refptr<SessionStorageNamespaceImpl>
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.h b/content/browser/dom_storage/dom_storage_context_wrapper.h
index 7287a8e64..5ab6db92 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <string>
 
+#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/memory_pressure_listener.h"
 #include "base/memory/ref_counted.h"
@@ -104,9 +105,10 @@
       mojo::ReportBadMessageCallback bad_message_callback,
       mojo::PendingReceiver<blink::mojom::SessionStorageNamespace> receiver);
 
-  void SetLocalStorageDatabaseFactoryForTesting(
-      base::RepeatingCallback<
-          std::unique_ptr<leveldb::mojom::LevelDBDatabase>()>);
+  using LocalStorageDatabaseOpenCallback =
+      base::OnceCallback<void(LocalStorageContextMojo*)>;
+  void SetLocalStorageDatabaseOpenCallbackForTesting(
+      LocalStorageDatabaseOpenCallback callback);
 
   SessionStorageContextMojo* mojo_session_state() {
     return mojo_session_state_;
diff --git a/content/browser/dom_storage/local_storage_context_mojo.cc b/content/browser/dom_storage/local_storage_context_mojo.cc
index b51b7ab..b42b0a9 100644
--- a/content/browser/dom_storage/local_storage_context_mojo.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo.cc
@@ -102,7 +102,8 @@
 void MigrateStorageHelper(
     base::FilePath db_path,
     const scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner,
-    base::Callback<void(std::unique_ptr<StorageAreaImpl::ValueMap>)> callback) {
+    base::OnceCallback<void(std::unique_ptr<StorageAreaImpl::ValueMap>)>
+        callback) {
   DOMStorageDatabase db(db_path);
   DOMStorageValuesMap map;
   db.ReadAllValues(&map);
@@ -282,7 +283,7 @@
           base::BindOnce(
               &MigrateStorageHelper, sql_db_path(),
               base::ThreadTaskRunnerHandle::Get(),
-              base::Bind(&CallMigrationCalback, base::Passed(&callback))));
+              base::BindOnce(&CallMigrationCalback, base::Passed(&callback))));
       return;
     }
     std::move(callback).Run(nullptr);
@@ -674,6 +675,11 @@
   return result;
 }
 
+void LocalStorageContextMojo::SetDatabaseOpenCallbackForTesting(
+    base::OnceClosure callback) {
+  RunWhenConnected(std::move(callback));
+}
+
 LocalStorageContextMojo::~LocalStorageContextMojo() {
   DCHECK_EQ(connection_state_, CONNECTION_SHUTDOWN);
   base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
@@ -701,13 +707,6 @@
 void LocalStorageContextMojo::InitiateConnection(bool in_memory_only) {
   DCHECK_EQ(connection_state_, CONNECTION_IN_PROGRESS);
 
-  if (database_factory_for_testing_) {
-    in_memory_ = true;
-    database_ = database_factory_for_testing_.Run();
-    OnDatabaseOpened(leveldb::mojom::DatabaseError::OK);
-    return;
-  }
-
   if (!directory_.empty() && directory_.IsAbsolute() && !in_memory_only) {
     // We were given a subdirectory to write to, so use a disk-backed database.
     leveldb_env::Options options;
diff --git a/content/browser/dom_storage/local_storage_context_mojo.h b/content/browser/dom_storage/local_storage_context_mojo.h
index 99ddf539..66afada 100644
--- a/content/browser/dom_storage/local_storage_context_mojo.h
+++ b/content/browser/dom_storage/local_storage_context_mojo.h
@@ -15,9 +15,12 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/sequenced_task_runner.h"
+#include "base/threading/sequence_bound.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_dump_provider.h"
+#include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/mojom/leveldb.mojom.h"
+#include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/dom_storage_task_runner.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_thread.h"
@@ -95,12 +98,6 @@
   // Clears unused storage areas, when thresholds are reached.
   void PurgeUnusedAreasIfNeeded();
 
-  using DatabaseFactory = base::RepeatingCallback<
-      std::unique_ptr<leveldb::mojom::LevelDBDatabase>()>;
-  void SetDatabaseFactoryForTesting(DatabaseFactory factory) {
-    database_factory_for_testing_ = std::move(factory);
-  }
-
   // base::trace_event::MemoryDumpProvider implementation.
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                     base::trace_event::ProcessMemoryDump* pmd) override;
@@ -112,6 +109,17 @@
     return task_runner_;
   }
 
+  // Access the underlying DomStorageDatabase. May be null if the database is
+  // not yet open.
+  const base::SequenceBound<storage::DomStorageDatabase>&
+  GetDatabaseForTesting() const {
+    return database_->database();
+  }
+
+  // Wait for the database to be opened, or for opening to fail. If the database
+  // is already opened, |callback| is invoked immediately.
+  void SetDatabaseOpenCallbackForTesting(base::OnceClosure callback);
+
  private:
   friend class DOMStorageBrowserTest;
 
@@ -183,7 +191,7 @@
 
   base::trace_event::MemoryAllocatorDumpGuid memory_dump_id_;
 
-  std::unique_ptr<leveldb::mojom::LevelDBDatabase> database_;
+  std::unique_ptr<leveldb::LevelDBDatabaseImpl> database_;
   bool tried_to_recreate_during_open_ = false;
   bool in_memory_ = false;
 
@@ -205,8 +213,6 @@
   // Name of an extra histogram to log open results to, if not null.
   const char* open_result_histogram_ = nullptr;
 
-  DatabaseFactory database_factory_for_testing_;
-
   base::WeakPtrFactory<LocalStorageContextMojo> weak_ptr_factory_{this};
 };
 
diff --git a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
index 7522eaf..ca133bf 100644
--- a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/containers/span.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -18,13 +19,11 @@
 #include "content/browser/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/dom_storage_task_runner.h"
 #include "content/browser/dom_storage/dom_storage_types.h"
-#include "content/browser/dom_storage/test/fake_leveldb_database_error_on_write.h"
 #include "content/browser/dom_storage/test/storage_area_test_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_usage_info.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_utils.h"
-#include "content/test/fake_leveldb_database.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
@@ -42,7 +41,6 @@
 namespace content {
 
 namespace {
-using test::FakeLevelDBDatabaseErrorOnWrite;
 
 void GetStorageUsageCallback(const base::RepeatingClosure& callback,
                              std::vector<StorageUsageInfo>* out_result,
@@ -114,6 +112,10 @@
     if (context_)
       ShutdownContext();
 
+    // Ensure any opened database is really closed before attempting to delete
+    // its storage path.
+    RunUntilIdle();
+
     EXPECT_TRUE(temp_path_.Delete());
   }
 
@@ -124,10 +126,6 @@
           task_runner_, temp_path_.GetPath(),
           base::FilePath(FILE_PATH_LITERAL("leveldb")),
           special_storage_policy());
-      context_->SetDatabaseFactoryForTesting(base::BindLambdaForTesting(
-          [&]() -> std::unique_ptr<leveldb::mojom::LevelDBDatabase> {
-            return std::make_unique<FakeLevelDBDatabase>(&mock_data_);
-          }));
     }
 
     return context_;
@@ -136,21 +134,70 @@
   void ShutdownContext() {
     context_->ShutdownAndDelete();
     context_ = nullptr;
-    base::RunLoop().RunUntilIdle();
+    RunUntilIdle();
   }
 
   MockSpecialStoragePolicy* special_storage_policy() {
     return mock_special_storage_policy_.get();
   }
 
-  const std::map<std::vector<uint8_t>, std::vector<uint8_t>>& mock_data() {
-    return mock_data_;
+  void WaitForDatabaseOpen() {
+    base::RunLoop loop;
+    context()->SetDatabaseOpenCallbackForTesting(loop.QuitClosure());
+    loop.Run();
   }
 
-  void clear_mock_data() { mock_data_.clear(); }
+  void SetDatabaseEntry(base::StringPiece key, base::StringPiece value) {
+    WaitForDatabaseOpen();
+    base::RunLoop loop;
+    context()->GetDatabaseForTesting().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          leveldb::Status status =
+              db.Put(base::as_bytes(base::make_span(key)),
+                     base::as_bytes(base::make_span(value)));
+          ASSERT_TRUE(status.ok());
+          loop.Quit();
+        }));
+    loop.Run();
+  }
 
-  void set_mock_data(const std::string& key, const std::string& value) {
-    mock_data_[StdStringToUint8Vector(key)] = StdStringToUint8Vector(value);
+  void ClearDatabase() {
+    WaitForDatabaseOpen();
+    base::RunLoop loop;
+    context()->GetDatabaseForTesting().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          leveldb::WriteBatch batch;
+          leveldb::Status status = db.DeletePrefixed({}, &batch);
+          ASSERT_TRUE(status.ok());
+          status = db.Commit(&batch);
+          ASSERT_TRUE(status.ok());
+          loop.Quit();
+        }));
+    loop.Run();
+  }
+
+  std::map<std::string, std::string> GetDatabaseContents() {
+    std::vector<storage::DomStorageDatabase::KeyValuePair> entries;
+    WaitForDatabaseOpen();
+    base::RunLoop loop;
+    context()->GetDatabaseForTesting().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          leveldb::Status status = db.GetPrefixed({}, &entries);
+          ASSERT_TRUE(status.ok());
+          loop.Quit();
+        }));
+    loop.Run();
+
+    std::map<std::string, std::string> contents;
+    for (auto& entry : entries) {
+      contents.emplace(std::string(entry.key.begin(), entry.key.end()),
+                       std::string(entry.value.begin(), entry.value.end()));
+    }
+
+    return contents;
   }
 
   std::vector<StorageUsageInfo> GetStorageUsageSync() {
@@ -178,6 +225,9 @@
   }
 
   const base::FilePath& temp_path() const { return temp_path_.GetPath(); }
+
+  // Pumps both the main-thread sequence and the background database sequence
+  // until both are idle.
   void RunUntilIdle() { task_environment_.RunUntilIdle(); }
 
   void DoTestPut(LocalStorageContextMojo* context,
@@ -243,7 +293,6 @@
 
   BrowserTaskEnvironment task_environment_;
   base::ScopedTempDir temp_path_;
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_;
 
   scoped_refptr<MockDOMStorageTaskRunner> task_runner_;
 
@@ -261,14 +310,15 @@
   mojo::Remote<blink::mojom::StorageArea> area;
   context()->OpenLocalStorage(url::Origin::Create(GURL("http://foobar.com")),
                               area.BindNewPipeAndPassReceiver());
+
   area->Put(key, value, base::nullopt, "source", base::DoNothing());
   area.reset();
 
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   // Should have three rows of data, one for the version, one for the actual
   // data and one for metadata.
-  ASSERT_EQ(3u, mock_data().size());
+  EXPECT_EQ(3u, GetDatabaseContents().size());
 }
 
 TEST_F(LocalStorageContextMojoTest, OriginsAreIndependent) {
@@ -280,6 +330,7 @@
 
   mojo::Remote<blink::mojom::StorageArea> area;
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
+
   area->Put(key1, value, base::nullopt, "source", base::DoNothing());
   area.reset();
 
@@ -287,8 +338,8 @@
   area->Put(key2, value, base::nullopt, "source", base::DoNothing());
   area.reset();
 
-  base::RunLoop().RunUntilIdle();
-  ASSERT_EQ(5u, mock_data().size());
+  RunUntilIdle();
+  EXPECT_EQ(5u, GetDatabaseContents().size());
 }
 
 TEST_F(LocalStorageContextMojoTest, WrapperOutlivesMojoConnection) {
@@ -303,13 +354,14 @@
   context()->OpenLocalStorage(kOrigin, area.BindNewPipeAndPassReceiver());
   context()->OpenLocalStorage(kOrigin, dummy_area.BindNewPipeAndPassReceiver());
   area->Put(key, value, base::nullopt, "source", base::DoNothing());
+
   area.reset();
   dummy_area.reset();
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   // Clear all the data from the backing database.
-  EXPECT_FALSE(mock_data().empty());
-  clear_mock_data();
+  EXPECT_FALSE(GetDatabaseContents().empty());
+  ClearDatabase();
 
   // Data should still be readable, because despite closing the area
   // connection above, the actual area instance should have been kept alive.
@@ -331,12 +383,13 @@
   context()->OpenLocalStorage(url::Origin::Create(GURL("http://foobar.com")),
                               area.BindNewPipeAndPassReceiver());
   area->Put(key, value, base::nullopt, "source", base::DoNothing());
+
   area.reset();
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   // Clear all the data from the backing database.
-  EXPECT_FALSE(mock_data().empty());
-  clear_mock_data();
+  EXPECT_FALSE(GetDatabaseContents().empty());
+  ClearDatabase();
 
   // Now open many new areas (for different origins) to trigger clean up.
   for (int i = 1; i <= 100; ++i) {
@@ -346,29 +399,37 @@
     area.reset();
   }
 
+  RunUntilIdle();
+
   // And make sure caches were actually cleared.
   EXPECT_EQ(base::nullopt, DoTestGet(key));
 }
 
 TEST_F(LocalStorageContextMojoTest, ValidVersion) {
-  set_mock_data("VERSION", "1");
-  set_mock_data(std::string("_http://foobar.com") + '\x00' + "key", "value");
+  SetDatabaseEntry("VERSION", "1");
+  SetDatabaseEntry(std::string("_http://foobar.com") + '\x00' + "key", "value");
+  ShutdownContext();
 
   EXPECT_EQ(StdStringToUint8Vector("value"),
             DoTestGet(StdStringToUint8Vector("key")));
 }
 
 TEST_F(LocalStorageContextMojoTest, InvalidVersion) {
-  set_mock_data("VERSION", "foobar");
-  set_mock_data(std::string("_http://foobar.com") + '\x00' + "key", "value");
+  SetDatabaseEntry("VERSION", "foobar");
+  SetDatabaseEntry(std::string("_http://foobar.com") + '\x00' + "key", "value");
+
+  // Force the context to reload the database, which should fail due to invalid
+  // version data.
+  ShutdownContext();
+
   EXPECT_EQ(base::nullopt, DoTestGet(StdStringToUint8Vector("key")));
 }
 
 TEST_F(LocalStorageContextMojoTest, VersionOnlyWrittenOnCommit) {
   EXPECT_EQ(base::nullopt, DoTestGet(StdStringToUint8Vector("key")));
 
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(mock_data().empty());
+  RunUntilIdle();
+  EXPECT_TRUE(GetDatabaseContents().empty());
 }
 
 TEST_F(LocalStorageContextMojoTest, GetStorageUsage_NoData) {
@@ -387,6 +448,7 @@
 
   mojo::Remote<blink::mojom::StorageArea> area;
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
+
   area->Put(key1, value, base::nullopt, "source", base::DoNothing());
   area->Put(key2, value, base::nullopt, "source", base::DoNothing());
   area.reset();
@@ -396,7 +458,7 @@
   area.reset();
 
   // Make sure all data gets committed to disk.
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   base::Time after_write = base::Time::Now();
 
@@ -421,6 +483,7 @@
 
   mojo::Remote<blink::mojom::StorageArea> area;
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
+
   area->Put(key, value, base::nullopt, "source", base::DoNothing());
   area.reset();
   context()->OpenLocalStorage(origin2, area.BindNewPipeAndPassReceiver());
@@ -431,18 +494,17 @@
   area.reset();
 
   // Make sure all data gets committed to disk.
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   // Data from origin2 should exist, including meta-data, but nothing should
   // exist for origin1.
-  EXPECT_EQ(3u, mock_data().size());
-  for (const auto& it : mock_data()) {
-    if (Uint8VectorToStdString(it.first) == "VERSION")
+  auto contents = GetDatabaseContents();
+  EXPECT_EQ(3u, contents.size());
+  for (const auto& entry : contents) {
+    if (entry.first == "VERSION")
       continue;
-    EXPECT_EQ(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin1.Serialize()));
-    EXPECT_NE(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin2.Serialize()));
+    EXPECT_EQ(std::string::npos, entry.first.find(origin1.Serialize()));
+    EXPECT_NE(std::string::npos, entry.first.find(origin2.Serialize()));
   }
 }
 
@@ -454,6 +516,7 @@
 
   mojo::Remote<blink::mojom::StorageArea> area;
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
+
   area->Put(key, value, base::nullopt, "source", base::DoNothing());
   area.reset();
   context()->OpenLocalStorage(origin2, area.BindNewPipeAndPassReceiver());
@@ -465,30 +528,30 @@
   area.reset();
 
   // Make sure all data gets committed to disk.
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   // Data from origin2 should exist, including meta-data, but nothing should
   // exist for origin1.
-  EXPECT_EQ(3u, mock_data().size());
-  for (const auto& it : mock_data()) {
-    if (Uint8VectorToStdString(it.first) == "VERSION")
+  auto contents = GetDatabaseContents();
+  EXPECT_EQ(3u, contents.size());
+  for (const auto& entry : contents) {
+    if (entry.first == "VERSION")
       continue;
-    EXPECT_EQ(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin1.Serialize()));
-    EXPECT_NE(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin2.Serialize()));
+    EXPECT_EQ(std::string::npos, entry.first.find(origin1.Serialize()));
+    EXPECT_NE(std::string::npos, entry.first.find(origin2.Serialize()));
   }
 }
 
 TEST_F(LocalStorageContextMojoTest, DeleteStorage) {
-  set_mock_data("VERSION", "1");
-  set_mock_data(std::string("_http://foobar.com") + '\x00' + "key", "value");
+  SetDatabaseEntry("VERSION", "1");
+  SetDatabaseEntry(std::string("_http://foobar.com") + '\x00' + "key", "value");
+  ShutdownContext();
 
   base::RunLoop run_loop;
   context()->DeleteStorage(url::Origin::Create(GURL("http://foobar.com")),
                            run_loop.QuitClosure());
   run_loop.Run();
-  EXPECT_EQ(1u, mock_data().size());
+  EXPECT_EQ(1u, GetDatabaseContents().size());
 }
 
 TEST_F(LocalStorageContextMojoTest, DeleteStorageWithoutConnection) {
@@ -499,6 +562,7 @@
 
   mojo::Remote<blink::mojom::StorageArea> area;
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
+
   area->Put(key, value, base::nullopt, "source", base::DoNothing());
   area.reset();
 
@@ -507,22 +571,21 @@
   area.reset();
 
   // Make sure all data gets committed to disk.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(mock_data().empty());
+  RunUntilIdle();
+  EXPECT_FALSE(GetDatabaseContents().empty());
 
   context()->DeleteStorage(origin1, base::DoNothing());
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   // Data from origin2 should exist, including meta-data, but nothing should
   // exist for origin1.
-  EXPECT_EQ(3u, mock_data().size());
-  for (const auto& it : mock_data()) {
-    if (Uint8VectorToStdString(it.first) == "VERSION")
+  auto contents = GetDatabaseContents();
+  EXPECT_EQ(3u, contents.size());
+  for (const auto& entry : contents) {
+    if (entry.first == "VERSION")
       continue;
-    EXPECT_EQ(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin1.Serialize()));
-    EXPECT_NE(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin2.Serialize()));
+    EXPECT_EQ(std::string::npos, entry.first.find(origin1.Serialize()));
+    EXPECT_NE(std::string::npos, entry.first.find(origin2.Serialize()));
   }
 }
 
@@ -534,6 +597,7 @@
 
   mojo::Remote<blink::mojom::StorageArea> area;
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
+
   area->Put(key, value, base::nullopt, "source", base::DoNothing());
   area.reset();
 
@@ -542,16 +606,16 @@
   area.reset();
 
   // Make sure all data gets committed to disk.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(mock_data().empty());
+  RunUntilIdle();
+  EXPECT_FALSE(GetDatabaseContents().empty());
 
   TestLevelDBObserver observer;
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
   area->AddObserver(observer.Bind());
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   context()->DeleteStorage(origin1, base::DoNothing());
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   ASSERT_EQ(1u, observer.observations().size());
   EXPECT_EQ(TestLevelDBObserver::Observation::kDeleteAll,
@@ -559,14 +623,13 @@
 
   // Data from origin2 should exist, including meta-data, but nothing should
   // exist for origin1.
-  EXPECT_EQ(3u, mock_data().size());
-  for (const auto& it : mock_data()) {
-    if (Uint8VectorToStdString(it.first) == "VERSION")
+  auto contents = GetDatabaseContents();
+  EXPECT_EQ(3u, contents.size());
+  for (const auto& entry : contents) {
+    if (entry.first == "VERSION")
       continue;
-    EXPECT_EQ(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin1.Serialize()));
-    EXPECT_NE(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin2.Serialize()));
+    EXPECT_EQ(std::string::npos, entry.first.find(origin1.Serialize()));
+    EXPECT_NE(std::string::npos, entry.first.find(origin2.Serialize()));
   }
 }
 
@@ -578,6 +641,7 @@
 
   mojo::Remote<blink::mojom::StorageArea> area;
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
+
   area->Put(key, value, base::nullopt, "source", base::DoNothing());
   area.reset();
 
@@ -586,18 +650,18 @@
   area.reset();
 
   // Make sure all data gets committed to disk.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(mock_data().empty());
+  RunUntilIdle();
+  EXPECT_FALSE(GetDatabaseContents().empty());
 
   TestLevelDBObserver observer;
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
   area->AddObserver(observer.Bind());
   area->Put(StdStringToUint8Vector("key2"), value, base::nullopt, "source",
             base::DoNothing());
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   context()->DeleteStorage(origin1, base::DoNothing());
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   ASSERT_EQ(2u, observer.observations().size());
   EXPECT_EQ(TestLevelDBObserver::Observation::kAdd,
@@ -607,14 +671,13 @@
 
   // Data from origin2 should exist, including meta-data, but nothing should
   // exist for origin1.
-  EXPECT_EQ(3u, mock_data().size());
-  for (const auto& it : mock_data()) {
-    if (Uint8VectorToStdString(it.first) == "VERSION")
+  auto contents = GetDatabaseContents();
+  EXPECT_EQ(3u, contents.size());
+  for (const auto& entry : contents) {
+    if (entry.first == "VERSION")
       continue;
-    EXPECT_EQ(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin1.Serialize()));
-    EXPECT_NE(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin2.Serialize()));
+    EXPECT_EQ(std::string::npos, entry.first.find(origin1.Serialize()));
+    EXPECT_NE(std::string::npos, entry.first.find(origin2.Serialize()));
   }
 }
 
@@ -649,15 +712,21 @@
   area->Get(std::vector<uint8_t>(), base::DoNothing());
   area.reset();
   dummy_area.reset();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(mock_data().empty());
+  RunUntilIdle();
+
+  EXPECT_TRUE(GetDatabaseContents().empty());
 
   // Opening origin1 and accessing its data should migrate its storage.
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
   context()->OpenLocalStorage(origin1, dummy_area.BindNewPipeAndPassReceiver());
-  area->Get(std::vector<uint8_t>(), base::DoNothing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(mock_data().empty());
+
+  base::RunLoop loop;
+  area->Get(std::vector<uint8_t>(),
+            base::BindLambdaForTesting(
+                [&](bool, const std::vector<uint8_t>&) { loop.Quit(); }));
+  loop.Run();
+
+  EXPECT_FALSE(GetDatabaseContents().empty());
 
   {
     std::vector<uint8_t> result;
@@ -690,19 +759,19 @@
 }
 
 TEST_F(LocalStorageContextMojoTest, FixUp) {
-  set_mock_data("VERSION", "1");
+  SetDatabaseEntry("VERSION", "1");
   // Add mock data for the "key" key, with both possible encodings for key.
   // We expect the value of the correctly encoded key to take precedence over
   // the incorrectly encoded key (and expect the incorrectly encoded key to be
   // deleted.
-  set_mock_data(std::string("_http://foobar.com") + '\x00' + "\x01key",
-                "value1");
-  set_mock_data(
+  SetDatabaseEntry(std::string("_http://foobar.com") + '\x00' + "\x01key",
+                   "value1");
+  SetDatabaseEntry(
       EncodeKeyAsUTF16("http://foobar.com", base::ASCIIToUTF16("key")),
       "value2");
   // Also add mock data for the "foo" key, this time only with the incorrec
   // encoding. This should be updated to the correct encoding.
-  set_mock_data(
+  SetDatabaseEntry(
       EncodeKeyAsUTF16("http://foobar.com", base::ASCIIToUTF16("foo")),
       "value3");
 
@@ -733,11 +802,10 @@
 
   // Expect 4 rows in the database: VERSION, meta-data for the origin, and two
   // rows of actual data.
-  EXPECT_EQ(4u, mock_data().size());
-  EXPECT_EQ(leveldb::StdStringToUint8Vector("value1"),
-            mock_data().rbegin()->second);
-  EXPECT_EQ(leveldb::StdStringToUint8Vector("value3"),
-            std::next(mock_data().rbegin())->second);
+  auto contents = GetDatabaseContents();
+  EXPECT_EQ(4u, contents.size());
+  EXPECT_EQ("value1", contents.rbegin()->second);
+  EXPECT_EQ("value3", std::next(contents.rbegin())->second);
 }
 
 TEST_F(LocalStorageContextMojoTest, ShutdownClearsData) {
@@ -749,6 +817,7 @@
 
   mojo::Remote<blink::mojom::StorageArea> area;
   context()->OpenLocalStorage(origin1, area.BindNewPipeAndPassReceiver());
+
   area->Put(key1, value, base::nullopt, "source", base::DoNothing());
   area->Put(key2, value, base::nullopt, "source", base::DoNothing());
   area.reset();
@@ -758,21 +827,20 @@
   area.reset();
 
   // Make sure all data gets committed to the DB.
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   special_storage_policy()->AddSessionOnly(origin1.GetURL());
   ShutdownContext();
 
   // Data from origin2 should exist, including meta-data, but nothing should
   // exist for origin1.
-  EXPECT_EQ(3u, mock_data().size());
-  for (const auto& it : mock_data()) {
-    if (Uint8VectorToStdString(it.first) == "VERSION")
+  auto contents = GetDatabaseContents();
+  EXPECT_EQ(3u, contents.size());
+  for (const auto& entry : contents) {
+    if (entry.first == "VERSION")
       continue;
-    EXPECT_EQ(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin1.Serialize()));
-    EXPECT_NE(std::string::npos,
-              Uint8VectorToStdString(it.first).find(origin2.Serialize()));
+    EXPECT_EQ(std::string::npos, entry.first.find(origin1.Serialize()));
+    EXPECT_NE(std::string::npos, entry.first.find(origin2.Serialize()));
   }
 }
 
@@ -966,7 +1034,6 @@
 }
 
 TEST_F(LocalStorageContextMojoTest, RecreateOnCommitFailure) {
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>> test_data;
   base::FilePath test_path(FILE_PATH_LITERAL("test_path"));
   auto* context = new LocalStorageContextMojo(
       temp_path(), base::ThreadTaskRunnerHandle::Get(), nullptr,
@@ -974,21 +1041,11 @@
 
   base::Optional<base::RunLoop> open_loop;
   base::Optional<base::RunLoop> destruction_loop;
-  bool first_database_destroyed = false;
   size_t num_database_open_requests = 0;
-  context->SetDatabaseFactoryForTesting(base::BindLambdaForTesting(
-      [&]() -> std::unique_ptr<leveldb::mojom::LevelDBDatabase> {
-        ++num_database_open_requests;
-        auto db = std::make_unique<FakeLevelDBDatabaseErrorOnWrite>(&test_data);
-        db->SetDestructionCallback(base::BindLambdaForTesting([&] {
-          first_database_destroyed = true;
-          if (destruction_loop)
-            destruction_loop->Quit();
-        }));
-        if (open_loop)
-          open_loop->Quit();
-        return db;
-      }));
+  context->SetDatabaseOpenCallbackForTesting(base::BindLambdaForTesting([&] {
+    ++num_database_open_requests;
+    open_loop->Quit();
+  }));
 
   auto key = StdStringToUint8Vector("key");
   auto value = StdStringToUint8Vector("value");
@@ -1022,18 +1079,25 @@
   // destroyed, which should happen after many commit failures.
   destruction_loop.emplace();
 
-  // Also prepare for another database connection, next time providing a
-  // functioning database.
+  bool first_database_destroyed = false;
+  context->GetDatabaseForTesting().PostTaskWithThisObject(
+      FROM_HERE,
+      base::BindLambdaForTesting([&](storage::DomStorageDatabase* db) {
+        db->MakeAllCommitsFailForTesting();
+        db->SetDestructionCallbackForTesting(base::BindLambdaForTesting([&] {
+          first_database_destroyed = true;
+          destruction_loop->Quit();
+        }));
+      }));
+
+  // Also prepare for another database connection, this time without making
+  // commits fail.
   open_loop.emplace();
   num_database_open_requests = 0;
-  context->SetDatabaseFactoryForTesting(base::BindLambdaForTesting(
-      [&]() -> std::unique_ptr<leveldb::mojom::LevelDBDatabase> {
-        ++num_database_open_requests;
-        auto db = std::make_unique<FakeLevelDBDatabase>(&test_data);
-        if (open_loop)
-          open_loop->Quit();
-        return db;
-      }));
+  context->SetDatabaseOpenCallbackForTesting(base::BindLambdaForTesting([&] {
+    ++num_database_open_requests;
+    open_loop->Quit();
+  }));
 
   // Start a put operation on the third connection before starting to commit
   // a lot of data on the first origin. This put operation should result in a
@@ -1044,17 +1108,14 @@
   // Repeatedly write data to the database, to trigger enough commit errors.
   size_t values_written = 0;
   while (area1.is_connected()) {
-    base::RunLoop put_loop;
     // Every write needs to be different to make sure there actually is a
-    // change to commit.
     value[0]++;
-    area1.set_disconnect_handler(put_loop.QuitClosure());
     area1->Put(key, value, base::nullopt, "source",
                base::BindLambdaForTesting([&](bool success) {
                  EXPECT_TRUE(success);
                  values_written++;
                }));
-    put_loop.RunUntilIdle();
+    RunUntilIdle();
     // And we need to flush after every change. Otherwise changes get batched up
     // and only one commit is done some time later.
     context->FlushOriginForTesting(
@@ -1101,7 +1162,6 @@
     std::vector<uint8_t> result;
     EXPECT_TRUE(DoTestGet(context, key, &result));
     EXPECT_EQ(value, result);
-    EXPECT_FALSE(test_data.empty());
   }
 
   // Observers should have seen one Add event and a number of Change events for
@@ -1113,11 +1173,11 @@
               observer2.observations()[i].type);
     EXPECT_EQ(Uint8VectorToStdString(key), observer2.observations()[i].key);
   }
+
+  context->ShutdownAndDelete();
 }
 
 TEST_F(LocalStorageContextMojoTest, DontRecreateOnRepeatedCommitFailure) {
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>> test_data;
-
   base::FilePath test_path(FILE_PATH_LITERAL("test_path"));
   auto* context = new LocalStorageContextMojo(
       temp_path(), base::ThreadTaskRunnerHandle::Get(), nullptr,
@@ -1127,16 +1187,10 @@
   base::Optional<base::RunLoop> open_loop;
   size_t num_database_open_requests = 0;
   size_t num_databases_destroyed = 0;
-  context->SetDatabaseFactoryForTesting(base::BindLambdaForTesting(
-      [&]() -> std::unique_ptr<leveldb::mojom::LevelDBDatabase> {
-        ++num_database_open_requests;
-        auto db = std::make_unique<FakeLevelDBDatabaseErrorOnWrite>(&test_data);
-        db->SetDestructionCallback(
-            base::BindLambdaForTesting([&] { ++num_databases_destroyed; }));
-        if (open_loop)
-          open_loop->Quit();
-        return db;
-      }));
+  context->SetDatabaseOpenCallbackForTesting(base::BindLambdaForTesting([&] {
+    ++num_database_open_requests;
+    open_loop->Quit();
+  }));
   open_loop.emplace();
 
   auto key = StdStringToUint8Vector("key");
@@ -1148,6 +1202,16 @@
                             area.BindNewPipeAndPassReceiver());
   open_loop->Run();
 
+  // Ensure that all commits fail on the database, and that we observe its
+  // destruction.
+  context->GetDatabaseForTesting().PostTaskWithThisObject(
+      FROM_HERE,
+      base::BindLambdaForTesting([&](storage::DomStorageDatabase* db) {
+        db->MakeAllCommitsFailForTesting();
+        db->SetDestructionCallbackForTesting(
+            base::BindLambdaForTesting([&] { ++num_databases_destroyed; }));
+      }));
+
   // Verify one attempt was made to open the database.
   ASSERT_EQ(1u, num_database_open_requests);
 
@@ -1159,18 +1223,15 @@
   // Repeatedly write data to the database, to trigger enough commit errors.
   base::Optional<std::vector<uint8_t>> old_value;
   while (area.is_connected()) {
-    base::RunLoop put_loop;
     // Every write needs to be different to make sure there actually is a
     // change to commit.
     value[0]++;
-    area.set_disconnect_handler(put_loop.QuitClosure());
     area->Put(key, value, old_value, "source",
               base::BindLambdaForTesting([&](bool success) {
                 EXPECT_TRUE(success);
-                put_loop.Quit();
               }));
     old_value = std::vector<uint8_t>(value);
-    put_loop.RunUntilIdle();
+    RunUntilIdle();
     // And we need to flush after every change. Otherwise changes get batched up
     // and only one commit is done some time later.
     context->FlushOriginForTesting(
@@ -1181,9 +1242,17 @@
   // Wait for LocalStorageContextMojo to try to reconnect to the database, and
   // connect that new request with a database implementation that always fails
   // on write.
+  context->SetDatabaseOpenCallbackForTesting(base::BindLambdaForTesting([&] {
+    ++num_database_open_requests;
+    open_loop->Quit();
+  }));
   open_loop->Run();
   EXPECT_EQ(2u, num_database_open_requests);
   EXPECT_EQ(1u, num_databases_destroyed);
+  context->GetDatabaseForTesting().PostTaskWithThisObject(
+      FROM_HERE, base::BindOnce([](storage::DomStorageDatabase* db) {
+        db->MakeAllCommitsFailForTesting();
+      }));
 
   // Reconnect a area to the database, and repeatedly write data to it again.
   // This time all should just keep getting written, and commit errors are
@@ -1192,17 +1261,14 @@
                             area.BindNewPipeAndPassReceiver());
   old_value = base::nullopt;
   for (int i = 0; i < 64; ++i) {
-    base::RunLoop put_loop;
     // Every write needs to be different to make sure there actually is a
     // change to commit.
     value[0]++;
-    area.set_disconnect_handler(put_loop.QuitClosure());
     area->Put(key, value, old_value, "source",
               base::BindLambdaForTesting([&](bool success) {
                 EXPECT_TRUE(success);
-                put_loop.Quit();
               }));
-    put_loop.RunUntilIdle();
+    RunUntilIdle();
     old_value = value;
     // And we need to flush after every change. Otherwise changes get batched up
     // and only one commit is done some time later.
@@ -1211,8 +1277,10 @@
   }
 
   // Should still be connected after all that.
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
   EXPECT_TRUE(area.is_connected());
+
+  context->ShutdownAndDelete();
 }
 
 }  // namespace content
diff --git a/content/browser/dom_storage/session_storage_area_impl_unittest.cc b/content/browser/dom_storage/session_storage_area_impl_unittest.cc
index 6c02c11..85d423ab 100644
--- a/content/browser/dom_storage/session_storage_area_impl_unittest.cc
+++ b/content/browser/dom_storage/session_storage_area_impl_unittest.cc
@@ -23,7 +23,6 @@
 #include "content/browser/dom_storage/session_storage_metadata.h"
 #include "content/browser/dom_storage/test/storage_area_test_util.h"
 #include "content/public/test/browser_task_environment.h"
-#include "content/test/fake_leveldb_database.h"
 #include "content/test/gmock_util.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
@@ -96,7 +95,7 @@
   const std::string test_namespace_id2_;
   const url::Origin test_origin1_;
   const url::Origin test_origin2_;
-  std::unique_ptr<leveldb::mojom::LevelDBDatabase> leveldb_database_;
+  std::unique_ptr<leveldb::LevelDBDatabaseImpl> leveldb_database_;
   SessionStorageMetadata metadata_;
 
   testing::StrictMock<MockListener> listener_;
diff --git a/content/browser/dom_storage/session_storage_context_mojo.cc b/content/browser/dom_storage/session_storage_context_mojo.cc
index d136b45..1a9a644 100644
--- a/content/browser/dom_storage/session_storage_context_mojo.cc
+++ b/content/browser/dom_storage/session_storage_context_mojo.cc
@@ -535,6 +535,11 @@
   it->second->FlushOriginForTesting(origin);
 }
 
+void SessionStorageContextMojo::SetDatabaseOpenCallbackForTesting(
+    base::OnceClosure callback) {
+  RunWhenConnected(std::move(callback));
+}
+
 scoped_refptr<SessionStorageMetadata::MapData>
 SessionStorageContextMojo::RegisterNewAreaMap(
     SessionStorageMetadata::NamespaceEntry namespace_entry,
@@ -698,13 +703,6 @@
 void SessionStorageContextMojo::InitiateConnection(bool in_memory_only) {
   DCHECK_EQ(connection_state_, CONNECTION_IN_PROGRESS);
 
-  if (database_factory_for_testing_) {
-    database_ = database_factory_for_testing_.Run();
-    in_memory_ = true;
-    OnDatabaseOpened(leveldb::mojom::DatabaseError::OK);
-    return;
-  }
-
   if (backing_mode_ != BackingMode::kNoDisk && !in_memory_only &&
       !partition_directory_.empty()) {
     // We were given a subdirectory to write to, so use a disk backed database.
diff --git a/content/browser/dom_storage/session_storage_context_mojo.h b/content/browser/dom_storage/session_storage_context_mojo.h
index 5ef022ba..438b8ac 100644
--- a/content/browser/dom_storage/session_storage_context_mojo.h
+++ b/content/browser/dom_storage/session_storage_context_mojo.h
@@ -18,8 +18,11 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/threading/sequence_bound.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_dump_provider.h"
+#include "components/services/leveldb/leveldb_database_impl.h"
+#include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/session_storage_data_map.h"
 #include "content/browser/dom_storage/session_storage_metadata.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl_mojo.h"
@@ -132,21 +135,24 @@
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                     base::trace_event::ProcessMemoryDump* pmd) override;
 
-  using DatabaseFactory = base::RepeatingCallback<
-      std::unique_ptr<leveldb::mojom::LevelDBDatabase>()>;
-  void SetDatabaseFactoryForTesting(DatabaseFactory factory) {
-    database_factory_for_testing_ = std::move(factory);
-  }
-
   void PretendToConnectForTesting();
 
-  leveldb::mojom::LevelDBDatabase* DatabaseForTesting() {
-    return database_.get();
-  }
+  leveldb::LevelDBDatabaseImpl* DatabaseForTesting() { return database_.get(); }
 
   void FlushAreaForTesting(const std::string& namespace_id,
                            const url::Origin& origin);
 
+  // Access the underlying DomStorageDatabase. May be null if the database is
+  // not yet open.
+  const base::SequenceBound<storage::DomStorageDatabase>&
+  GetDatabaseForTesting() const {
+    return database_->database();
+  }
+
+  // Wait for the database to be opened, or for opening to fail. If the database
+  // is already opened, |callback| is invoked immediately.
+  void SetDatabaseOpenCallbackForTesting(base::OnceClosure callback);
+
  private:
   friend class DOMStorageBrowserTest;
   FRIEND_TEST_ALL_PREFIXES(SessionStorageContextMojoTest,
@@ -250,7 +256,7 @@
 
   base::trace_event::MemoryAllocatorDumpGuid memory_dump_id_;
 
-  std::unique_ptr<leveldb::mojom::LevelDBDatabase> database_;
+  std::unique_ptr<leveldb::LevelDBDatabaseImpl> database_;
   bool in_memory_ = false;
   bool tried_to_recreate_during_open_ = false;
 
@@ -281,8 +287,6 @@
   // Name of an extra histogram to log open results to, if not null.
   const char* open_result_histogram_ = nullptr;
 
-  DatabaseFactory database_factory_for_testing_;
-
   base::WeakPtrFactory<SessionStorageContextMojo> weak_ptr_factory_{this};
 };
 
diff --git a/content/browser/dom_storage/session_storage_context_mojo_unittest.cc b/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
index f5826f06..1b7eb97 100644
--- a/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
+++ b/content/browser/dom_storage/session_storage_context_mojo_unittest.cc
@@ -23,7 +23,6 @@
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/dom_storage/dom_storage_types.h"
 #include "content/browser/dom_storage/session_storage_database.h"
-#include "content/browser/dom_storage/test/fake_leveldb_database_error_on_write.h"
 #include "content/browser/dom_storage/test/storage_area_test_util.h"
 #include "content/public/browser/session_storage_usage_info.h"
 #include "content/public/test/browser_task_environment.h"
@@ -66,7 +65,7 @@
 
     // There may be pending tasks to clean up files in the temp dir. Make sure
     // they run so temp dir deletion can succeed.
-    task_environment_.RunUntilIdle();
+    RunUntilIdle();
 
     EXPECT_TRUE(temp_dir_.Delete());
   }
@@ -113,7 +112,7 @@
   void ShutdownContext() {
     context_->ShutdownAndDelete();
     context_ = nullptr;
-    base::RunLoop().RunUntilIdle();
+    RunUntilIdle();
   }
 
   std::vector<SessionStorageUsageInfo> GetStorageUsageSync() {
@@ -658,22 +657,14 @@
   url::Origin origin2 = url::Origin::Create(GURL("http://asf.com"));
   url::Origin origin3 = url::Origin::Create(GURL("http://example.com"));
 
-  // Ensure that the first opened database always fails to write data.
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>> test_data;
   base::Optional<base::RunLoop> open_loop;
   size_t num_database_open_requests = 0;
   size_t num_databases_destroyed = 0;
-  context()->SetDatabaseFactoryForTesting(base::BindLambdaForTesting(
-      [&]() -> std::unique_ptr<leveldb::mojom::LevelDBDatabase> {
-        ++num_database_open_requests;
-        auto db =
-            std::make_unique<test::FakeLevelDBDatabaseErrorOnWrite>(&test_data);
-        db->SetDestructionCallback(
-            base::BindLambdaForTesting([&] { ++num_databases_destroyed; }));
-        if (open_loop)
-          open_loop->Quit();
-        return db;
-      }));
+  context()->SetDatabaseOpenCallbackForTesting(base::BindLambdaForTesting([&] {
+    ++num_database_open_requests;
+    open_loop->Quit();
+  }));
+
   open_loop.emplace();
 
   // Open three connections to the database.
@@ -691,6 +682,15 @@
   ss_namespace->OpenArea(origin3, area_o3.BindNewEndpointAndPassReceiver());
   open_loop->Run();
 
+  // Ensure that the first opened database always fails to write data.
+  context()->GetDatabaseForTesting().PostTaskWithThisObject(
+      FROM_HERE,
+      base::BindLambdaForTesting([&](storage::DomStorageDatabase* db) {
+        db->MakeAllCommitsFailForTesting();
+        db->SetDestructionCallbackForTesting(
+            base::BindLambdaForTesting([&] { ++num_databases_destroyed; }));
+      }));
+
   // Verify one attempt was made to open the database.
   ASSERT_EQ(1u, num_database_open_requests);
 
@@ -702,14 +702,10 @@
   // Also prepare for another database connection, next time providing a
   // functioning database.
   open_loop.emplace();
-  context()->SetDatabaseFactoryForTesting(base::BindLambdaForTesting(
-      [&]() -> std::unique_ptr<leveldb::mojom::LevelDBDatabase> {
-        ++num_database_open_requests;
-        auto db = std::make_unique<FakeLevelDBDatabase>(&test_data);
-        if (open_loop)
-          open_loop->Quit();
-        return db;
-      }));
+  context()->SetDatabaseOpenCallbackForTesting(base::BindLambdaForTesting([&] {
+    ++num_database_open_requests;
+    open_loop->Quit();
+  }));
 
   // Start a put operation on the third connection before starting to commit
   // a lot of data on the first origin. This put operation should result in a
@@ -724,19 +720,16 @@
   int i = 0;
   while (area_o1.is_connected()) {
     ++i;
-    base::RunLoop put_loop;
     // Every write needs to be different to make sure there actually is a
     // change to commit.
     std::vector<uint8_t> old_value = value;
     value[0]++;
-    area_o1.set_disconnect_handler(put_loop.QuitClosure());
-
     area_o1->Put(leveldb::StringPieceToUint8Vector("key"), value, base::nullopt,
                  "source", base::BindLambdaForTesting([&](bool success) {
                    EXPECT_TRUE(success);
                  }));
     area_o1.FlushForTesting();
-    put_loop.RunUntilIdle();
+    RunUntilIdle();
     // And we need to flush after every change. Otherwise changes get batched up
     // and only one commit is done some time later.
     context()->FlushAreaForTesting(namespace_id, origin1);
@@ -793,22 +786,13 @@
   std::string namespace_id = base::GenerateGUID();
   url::Origin origin1 = url::Origin::Create(GURL("http://foobar.com"));
 
-  // Ensure that any opened database always fails to write data.
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>> test_data;
   base::Optional<base::RunLoop> open_loop;
   size_t num_database_open_requests = 0;
   size_t num_databases_destroyed = 0;
-  context()->SetDatabaseFactoryForTesting(base::BindLambdaForTesting(
-      [&]() -> std::unique_ptr<leveldb::mojom::LevelDBDatabase> {
-        ++num_database_open_requests;
-        auto db =
-            std::make_unique<test::FakeLevelDBDatabaseErrorOnWrite>(&test_data);
-        db->SetDestructionCallback(
-            base::BindLambdaForTesting([&] { ++num_databases_destroyed; }));
-        if (open_loop)
-          open_loop->Quit();
-        return db;
-      }));
+  context()->SetDatabaseOpenCallbackForTesting(base::BindLambdaForTesting([&] {
+    ++num_database_open_requests;
+    open_loop->Quit();
+  }));
   open_loop.emplace();
 
   // Open three connections to the database.
@@ -822,6 +806,15 @@
   ss_namespace->OpenArea(origin1, area.BindNewEndpointAndPassReceiver());
   open_loop->Run();
 
+  // Ensure that this database always fails to write data.
+  context()->GetDatabaseForTesting().PostTaskWithThisObject(
+      FROM_HERE,
+      base::BindLambdaForTesting([&](storage::DomStorageDatabase* db) {
+        db->MakeAllCommitsFailForTesting();
+        db->SetDestructionCallbackForTesting(
+            base::BindLambdaForTesting([&] { ++num_databases_destroyed; }));
+      }));
+
   // Verify one attempt was made to open the database.
   EXPECT_EQ(1u, num_database_open_requests);
 
@@ -829,22 +822,27 @@
   // reconnect to the database, which should happen after several commit
   // errors.
   open_loop.emplace();
+  context()->SetDatabaseOpenCallbackForTesting(base::BindLambdaForTesting([&] {
+    ++num_database_open_requests;
+    open_loop->Quit();
+
+    // Ensure that this database also always fails to write data.
+    context()->GetDatabaseForTesting().Post(
+        FROM_HERE, &storage::DomStorageDatabase::MakeAllCommitsFailForTesting);
+  }));
 
   // Repeatedly write data to the database, to trigger enough commit errors.
   auto value = leveldb::StringPieceToUint8Vector("avalue");
   base::Optional<std::vector<uint8_t>> old_value = base::nullopt;
   while (area.is_connected()) {
-    base::RunLoop put_loop;
     // Every write needs to be different to make sure there actually is a
     // change to commit.
-    area.set_disconnect_handler(put_loop.QuitClosure());
     area->Put(leveldb::StringPieceToUint8Vector("key"), value, old_value,
               "source", base::BindLambdaForTesting([&](bool success) {
                 EXPECT_TRUE(success);
-                put_loop.Quit();
               }));
     area.FlushForTesting();
-    put_loop.RunUntilIdle();
+    RunUntilIdle();
     // And we need to flush after every change. Otherwise changes get batched up
     // and only one commit is done some time later.
     context()->FlushAreaForTesting(namespace_id, origin1);
@@ -862,8 +860,6 @@
   EXPECT_EQ(2u, num_database_open_requests);
   EXPECT_EQ(1u, num_databases_destroyed);
 
-  context()->SetDatabaseFactoryForTesting(base::NullCallback());
-
   // Reconnect a area to the database, and repeatedly write data to it again.
   // This time all should just keep getting written, and commit errors are
   // getting ignored.
@@ -875,17 +871,14 @@
 
   old_value = base::nullopt;
   for (int i = 0; i < 64; ++i) {
-    base::RunLoop put_loop;
     // Every write needs to be different to make sure there actually is a
     // change to commit.
-    area.set_disconnect_handler(put_loop.QuitClosure());
     area->Put(leveldb::StringPieceToUint8Vector("key"), value, old_value,
               "source", base::BindLambdaForTesting([&](bool success) {
                 EXPECT_TRUE(success);
-                put_loop.Quit();
               }));
     area.FlushForTesting();
-    put_loop.RunUntilIdle();
+    RunUntilIdle();
     // And we need to flush after every change. Otherwise changes get batched up
     // and only one commit is done some time later.
     context()->FlushAreaForTesting(namespace_id, origin1);
@@ -895,7 +888,7 @@
   }
 
   // Should still be connected after all that.
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
   EXPECT_TRUE(area.is_connected());
 
   context()->DeleteSessionNamespace(namespace_id, false);
@@ -1018,7 +1011,7 @@
     ss_namespace1->OpenArea(url::Origin::Create(GURL(base::StringPrintf(
                                 "http://example.com:%d", i))),
                             area.BindNewEndpointAndPassReceiver());
-    base::RunLoop().RunUntilIdle();
+    RunUntilIdle();
     ss_namespace1.reset();
     area.reset();
   }
@@ -1235,7 +1228,7 @@
   area_n2.reset();
   ss_namespace2.reset();
 
-  base::RunLoop().RunUntilIdle();
+  RunUntilIdle();
 
   // Verify this doesn't crash or hang.
   context()->PurgeMemory();
diff --git a/content/browser/dom_storage/session_storage_data_map.cc b/content/browser/dom_storage/session_storage_data_map.cc
index 33ced0c..49e3168 100644
--- a/content/browser/dom_storage/session_storage_data_map.cc
+++ b/content/browser/dom_storage/session_storage_data_map.cc
@@ -15,7 +15,7 @@
 scoped_refptr<SessionStorageDataMap> SessionStorageDataMap::CreateFromDisk(
     Listener* listener,
     scoped_refptr<SessionStorageMetadata::MapData> map_data,
-    leveldb::mojom::LevelDBDatabase* database) {
+    leveldb::LevelDBDatabaseImpl* database) {
   return base::WrapRefCounted(new SessionStorageDataMap(
       listener, std::move(map_data), database, false));
 }
@@ -24,7 +24,7 @@
 scoped_refptr<SessionStorageDataMap> SessionStorageDataMap::CreateEmpty(
     Listener* listener,
     scoped_refptr<SessionStorageMetadata::MapData> map_data,
-    leveldb::mojom::LevelDBDatabase* database) {
+    leveldb::LevelDBDatabaseImpl* database) {
   return base::WrapRefCounted(
       new SessionStorageDataMap(listener, std::move(map_data), database, true));
 }
@@ -50,7 +50,7 @@
 SessionStorageDataMap::SessionStorageDataMap(
     Listener* listener,
     scoped_refptr<SessionStorageMetadata::MapData> map_data,
-    leveldb::mojom::LevelDBDatabase* database,
+    leveldb::LevelDBDatabaseImpl* database,
     bool is_empty)
     : listener_(listener),
       map_data_(std::move(map_data)),
diff --git a/content/browser/dom_storage/session_storage_data_map.h b/content/browser/dom_storage/session_storage_data_map.h
index bc1f2c50..478835cb 100644
--- a/content/browser/dom_storage/session_storage_data_map.h
+++ b/content/browser/dom_storage/session_storage_data_map.h
@@ -16,6 +16,10 @@
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 
+namespace leveldb {
+class LevelDBDatabaseImpl;
+}
+
 namespace content {
 
 // Holds the StorageArea for a session storage data map. Every
@@ -44,12 +48,12 @@
   static scoped_refptr<SessionStorageDataMap> CreateFromDisk(
       Listener* listener,
       scoped_refptr<SessionStorageMetadata::MapData> map_data,
-      leveldb::mojom::LevelDBDatabase* database);
+      leveldb::LevelDBDatabaseImpl* database);
 
   static scoped_refptr<SessionStorageDataMap> CreateEmpty(
       Listener* listener,
       scoped_refptr<SessionStorageMetadata::MapData> map_data,
-      leveldb::mojom::LevelDBDatabase* database);
+      leveldb::LevelDBDatabaseImpl* database);
 
   static scoped_refptr<SessionStorageDataMap> CreateClone(
       Listener* listener,
@@ -83,7 +87,7 @@
   SessionStorageDataMap(
       Listener* listener,
       scoped_refptr<SessionStorageMetadata::MapData> map_entry,
-      leveldb::mojom::LevelDBDatabase* database,
+      leveldb::LevelDBDatabaseImpl* database,
       bool is_empty);
   SessionStorageDataMap(
       Listener* listener,
diff --git a/content/browser/dom_storage/session_storage_data_map_unittest.cc b/content/browser/dom_storage/session_storage_data_map_unittest.cc
index bc2ce77c..b8a7e121 100644
--- a/content/browser/dom_storage/session_storage_data_map_unittest.cc
+++ b/content/browser/dom_storage/session_storage_data_map_unittest.cc
@@ -8,12 +8,16 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/containers/span.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
+#include "base/task/post_task.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/task_environment.h"
+#include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/cpp/util.h"
+#include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/public/test/browser_task_environment.h"
-#include "content/test/fake_leveldb_database.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
@@ -26,6 +30,10 @@
 using leveldb::StdStringToUint8Vector;
 using leveldb::Uint8VectorToStdString;
 
+base::span<const uint8_t> MakeBytes(base::StringPiece str) {
+  return base::as_bytes(base::make_span(str));
+}
+
 class MockListener : public SessionStorageDataMap::Listener {
  public:
   MockListener() {}
@@ -79,23 +87,58 @@
 class SessionStorageDataMapTest : public testing::Test {
  public:
   SessionStorageDataMapTest()
-      : test_origin_(url::Origin::Create(GURL("http://host1.com:1"))),
-        database_(&mock_data_) {
-    // Should show up in first map.
-    mock_data_[StdStringToUint8Vector("map-1-key1")] =
-        StdStringToUint8Vector("data1");
-    // Dummy data to verify we don't delete everything.
-    mock_data_[StdStringToUint8Vector("map-3-key1")] =
-        StdStringToUint8Vector("data3");
+      : test_origin_(url::Origin::Create(GURL("http://host1.com:1"))) {
+    base::RunLoop loop;
+    database_ = leveldb::LevelDBDatabaseImpl::OpenInMemory(
+        base::nullopt, "SessionStorageDataMapTest",
+        base::CreateSequencedTaskRunner({base::MayBlock(), base::ThreadPool()}),
+        base::BindLambdaForTesting([&](leveldb::mojom::DatabaseError error) {
+          ASSERT_EQ(leveldb::mojom::DatabaseError::OK, error);
+          loop.Quit();
+        }));
+    loop.Run();
+
+    database_->database().PostTaskWithThisObject(
+        FROM_HERE, base::BindOnce([](const storage::DomStorageDatabase& db) {
+          // Should show up in first map.
+          leveldb::Status status =
+              db.Put(MakeBytes("map-1-key1"), MakeBytes("data1"));
+          ASSERT_TRUE(status.ok());
+
+          // Dummy data to verify we don't delete everything.
+          status = db.Put(MakeBytes("map-3-key1"), MakeBytes("data3"));
+          ASSERT_TRUE(status.ok());
+        }));
   }
-  ~SessionStorageDataMapTest() override {}
+
+  ~SessionStorageDataMapTest() override = default;
+
+  std::map<std::string, std::string> GetDatabaseContents() {
+    std::vector<storage::DomStorageDatabase::KeyValuePair> entries;
+    base::RunLoop loop;
+    database_->database().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          leveldb::Status status = db.GetPrefixed({}, &entries);
+          ASSERT_TRUE(status.ok());
+          loop.Quit();
+        }));
+    loop.Run();
+
+    std::map<std::string, std::string> contents;
+    for (auto& entry : entries) {
+      contents.emplace(std::string(entry.key.begin(), entry.key.end()),
+                       std::string(entry.value.begin(), entry.value.end()));
+    }
+
+    return contents;
+  }
 
  protected:
   BrowserTaskEnvironment task_environment_;
   testing::StrictMock<MockListener> listener_;
   url::Origin test_origin_;
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_;
-  FakeLevelDBDatabase database_;
+  std::unique_ptr<leveldb::LevelDBDatabaseImpl> database_;
 };
 
 }  // namespace
@@ -110,7 +153,7 @@
           &listener_,
           base::MakeRefCounted<SessionStorageMetadata::MapData>(1,
                                                                 test_origin_),
-          &database_);
+          database_.get());
 
   bool success;
   std::vector<blink::mojom::KeyValuePtr> data;
@@ -131,7 +174,7 @@
 
   // Test data is not cleared on deletion.
   map = nullptr;
-  EXPECT_EQ(2u, mock_data_.size());
+  EXPECT_EQ(2u, GetDatabaseContents().size());
 }
 
 TEST_F(SessionStorageDataMapTest, ExplicitlyEmpty) {
@@ -142,7 +185,7 @@
   scoped_refptr<SessionStorageDataMap> map = SessionStorageDataMap::CreateEmpty(
       &listener_,
       base::MakeRefCounted<SessionStorageMetadata::MapData>(1, test_origin_),
-      &database_);
+      database_.get());
 
   bool success;
   std::vector<blink::mojom::KeyValuePtr> data;
@@ -161,7 +204,7 @@
 
   // Test data is not cleared on deletion.
   map = nullptr;
-  EXPECT_EQ(2u, mock_data_.size());
+  EXPECT_EQ(2u, GetDatabaseContents().size());
 }
 
 TEST_F(SessionStorageDataMapTest, Clone) {
@@ -174,7 +217,7 @@
           &listener_,
           base::MakeRefCounted<SessionStorageMetadata::MapData>(1,
                                                                 test_origin_),
-          &database_);
+          database_.get());
 
   EXPECT_CALL(listener_,
               OnDataMapCreation(StdStringToUint8Vector("2"), testing::_))
@@ -205,9 +248,7 @@
   EXPECT_EQ(StdStringToUint8Vector("data1"), data[0]->value);
 
   // Test that the data was copied.
-  EXPECT_EQ(StdStringToUint8Vector("data1"),
-            mock_data_[StdStringToUint8Vector("map-2-key1")]);
-
+  EXPECT_EQ("data1", GetDatabaseContents()["map-2-key1"]);
   EXPECT_CALL(listener_, OnDataMapDestruction(StdStringToUint8Vector("1")))
       .Times(1);
   EXPECT_CALL(listener_, OnDataMapDestruction(StdStringToUint8Vector("2")))
@@ -216,7 +257,7 @@
   // Test data is not cleared on deletion.
   map1 = nullptr;
   map2 = nullptr;
-  EXPECT_EQ(3u, mock_data_.size());
+  EXPECT_EQ(3u, GetDatabaseContents().size());
 }
 
 }  // namespace content
diff --git a/content/browser/dom_storage/session_storage_metadata_unittest.cc b/content/browser/dom_storage/session_storage_metadata_unittest.cc
index 43b1d05..7495de72 100644
--- a/content/browser/dom_storage/session_storage_metadata_unittest.cc
+++ b/content/browser/dom_storage/session_storage_metadata_unittest.cc
@@ -12,12 +12,14 @@
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/task_environment.h"
+#include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/cpp/util.h"
 #include "content/browser/dom_storage/dom_storage_types.h"
 #include "content/browser/dom_storage/session_storage_database.h"
 #include "content/browser/indexed_db/leveldb/leveldb_env.h"
-#include "content/test/fake_leveldb_database.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -34,22 +36,10 @@
 using leveldb::Uint8VectorToStdString;
 using leveldb::mojom::DatabaseError;
 
-void GetCallback(std::vector<uint8_t>* value_out,
-                 DatabaseError error,
-                 const std::vector<uint8_t>& value) {
-  *value_out = value;
-}
-
 void ErrorCallback(DatabaseError* error_out, DatabaseError error) {
   *error_out = error;
 }
 
-void GetAllCallback(std::vector<leveldb::mojom::KeyValuePtr>* values_out,
-                    DatabaseError error,
-                    std::vector<leveldb::mojom::KeyValuePtr> values) {
-  *values_out = std::move(values);
-}
-
 class SessionStorageMetadataTest : public testing::Test {
  public:
   SessionStorageMetadataTest()
@@ -57,8 +47,15 @@
         test_namespace2_id_(base::GenerateGUID()),
         test_namespace3_id_(base::GenerateGUID()),
         test_origin1_(url::Origin::Create(GURL("http://host1:1/"))),
-        test_origin2_(url::Origin::Create(GURL("http://host2:2/"))),
-        database_(&mock_data_) {
+        test_origin2_(url::Origin::Create(GURL("http://host2:2/"))) {
+    base::RunLoop loop;
+    database_ = leveldb::LevelDBDatabaseImpl::OpenInMemory(
+        base::nullopt, "SessionStorageMetadataTest",
+        base::CreateSequencedTaskRunner({base::MayBlock(), base::ThreadPool()}),
+        base::BindLambdaForTesting(
+            [&](leveldb::mojom::DatabaseError) { loop.Quit(); }));
+    loop.Run();
+
     next_map_id_key_ = std::vector<uint8_t>(
         std::begin(SessionStorageMetadata::kNextMapIdKeyBytes),
         std::end(SessionStorageMetadata::kNextMapIdKeyBytes));
@@ -72,18 +69,36 @@
   ~SessionStorageMetadataTest() override {}
 
   void ReadMetadataFromDatabase(SessionStorageMetadata* metadata) {
-    std::vector<uint8_t> value;
-    database_.Get(database_version_key_, base::BindOnce(&GetCallback, &value));
+    std::vector<uint8_t> version_value;
+    std::vector<uint8_t> next_map_id_value;
+    std::vector<storage::DomStorageDatabase::KeyValuePair> namespace_entries;
+
+    base::RunLoop loop;
+    database_->database().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          EXPECT_TRUE(db.Get(database_version_key_, &version_value).ok());
+          EXPECT_TRUE(db.Get(next_map_id_key_, &next_map_id_value).ok());
+          EXPECT_TRUE(
+              db.GetPrefixed(namespaces_prefix_key_, &namespace_entries).ok());
+          loop.Quit();
+        }));
+    loop.Run();
+
     std::vector<leveldb::mojom::BatchedOperationPtr> migration_operations;
-    EXPECT_TRUE(metadata->ParseDatabaseVersion(value, &migration_operations));
-    EXPECT_TRUE(migration_operations.empty());
-    database_.Get(next_map_id_key_, base::BindOnce(&GetCallback, &value));
-    metadata->ParseNextMapId(value);
-    std::vector<leveldb::mojom::KeyValuePtr> values;
-    database_.GetPrefixed(namespaces_prefix_key_,
-                          base::BindOnce(&GetAllCallback, &values));
     EXPECT_TRUE(
-        metadata->ParseNamespaces(std::move(values), &migration_operations));
+        metadata->ParseDatabaseVersion(version_value, &migration_operations));
+    EXPECT_TRUE(migration_operations.empty());
+
+    metadata->ParseNextMapId(next_map_id_value);
+
+    std::vector<leveldb::mojom::KeyValuePtr> namespace_values;
+    for (auto& entry : namespace_entries) {
+      namespace_values.push_back(
+          leveldb::mojom::KeyValue::New(entry.key, entry.value));
+    }
+    EXPECT_TRUE(metadata->ParseNamespaces(std::move(namespace_values),
+                                          &migration_operations));
     EXPECT_TRUE(migration_operations.empty());
   }
 
@@ -99,29 +114,71 @@
     // | namespace-<guid 2>-http://host2:2/     | 4                  |
     // | next-map-id                            | 5                  |
     // | version                                | 1                  |
-    mock_data_[StdStringToUint8Vector(
-        std::string("namespace-") + test_namespace1_id_ + "-" +
-        test_origin1_.GetURL().spec())] = StdStringToUint8Vector("1");
-    mock_data_[StdStringToUint8Vector(
-        std::string("namespace-") + test_namespace1_id_ + "-" +
-        test_origin2_.GetURL().spec())] = StdStringToUint8Vector("3");
-    mock_data_[StdStringToUint8Vector(
-        std::string("namespace-") + test_namespace2_id_ + "-" +
-        test_origin1_.GetURL().spec())] = StdStringToUint8Vector("1");
-    mock_data_[StdStringToUint8Vector(
-        std::string("namespace-") + test_namespace2_id_ + "-" +
-        test_origin2_.GetURL().spec())] = StdStringToUint8Vector("4");
+    base::RunLoop loop;
+    database_->database().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          db.Put(StdStringToUint8Vector(std::string("namespace-") +
+                                        test_namespace1_id_ + "-" +
+                                        test_origin1_.GetURL().spec()),
+                 StdStringToUint8Vector("1"));
+          db.Put(StdStringToUint8Vector(std::string("namespace-") +
+                                        test_namespace1_id_ + "-" +
+                                        test_origin2_.GetURL().spec()),
+                 StdStringToUint8Vector("3"));
+          db.Put(StdStringToUint8Vector(std::string("namespace-") +
+                                        test_namespace2_id_ + "-" +
+                                        test_origin1_.GetURL().spec()),
+                 StdStringToUint8Vector("1"));
+          db.Put(StdStringToUint8Vector(std::string("namespace-") +
+                                        test_namespace2_id_ + "-" +
+                                        test_origin2_.GetURL().spec()),
+                 StdStringToUint8Vector("4"));
 
-    mock_data_[next_map_id_key_] = StdStringToUint8Vector("5");
+          db.Put(next_map_id_key_, StdStringToUint8Vector("5"));
 
-    mock_data_[StdStringToUint8Vector("map-1-key1")] =
-        StdStringToUint8Vector("data1");
-    mock_data_[StdStringToUint8Vector("map-3-key1")] =
-        StdStringToUint8Vector("data3");
-    mock_data_[StdStringToUint8Vector("map-4-key1")] =
-        StdStringToUint8Vector("data4");
+          db.Put(StdStringToUint8Vector("map-1-key1"),
+                 StdStringToUint8Vector("data1"));
+          db.Put(StdStringToUint8Vector("map-3-key1"),
+                 StdStringToUint8Vector("data3"));
+          db.Put(StdStringToUint8Vector("map-4-key1"),
+                 StdStringToUint8Vector("data4"));
 
-    mock_data_[database_version_key_] = StdStringToUint8Vector("1");
+          db.Put(database_version_key_, StdStringToUint8Vector("1"));
+          loop.Quit();
+        }));
+    loop.Run();
+  }
+
+  std::map<std::vector<uint8_t>, std::vector<uint8_t>> GetDatabaseContents() {
+    std::vector<storage::DomStorageDatabase::KeyValuePair> entries;
+    base::RunLoop loop;
+    database_->database().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          leveldb::Status status = db.GetPrefixed({}, &entries);
+          ASSERT_TRUE(status.ok());
+          loop.Quit();
+        }));
+    loop.Run();
+
+    std::map<std::vector<uint8_t>, std::vector<uint8_t>> contents;
+    for (auto& entry : entries)
+      contents.emplace(entry.key, entry.value);
+    return contents;
+  }
+
+  void WriteBatch(
+      std::vector<leveldb::mojom::BatchedOperationPtr> operations,
+      base::OnceCallback<void(leveldb::mojom::DatabaseError)> callback) {
+    base::RunLoop loop;
+    database_->Write(
+        std::move(operations),
+        base::BindLambdaForTesting([&](leveldb::mojom::DatabaseError error) {
+          std::move(callback).Run(error);
+          loop.Quit();
+        }));
+    loop.Run();
   }
 
  protected:
@@ -131,8 +188,7 @@
   std::string test_namespace3_id_;
   url::Origin test_origin1_;
   url::Origin test_origin2_;
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_;
-  FakeLevelDBDatabase database_;
+  std::unique_ptr<leveldb::LevelDBDatabaseImpl> database_;
 
   std::vector<uint8_t> database_version_key_;
   std::vector<uint8_t> next_map_id_key_;
@@ -145,12 +201,12 @@
       metadata.SetupNewDatabase();
 
   DatabaseError error;
-  database_.Write(std::move(operations),
-                  base::BindOnce(&ErrorCallback, &error));
+  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &error));
   EXPECT_EQ(DatabaseError::OK, error);
 
-  EXPECT_EQ(StdStringToUint8Vector("1"), mock_data_[database_version_key_]);
-  EXPECT_EQ(StdStringToUint8Vector("0"), mock_data_[next_map_id_key_]);
+  auto contents = GetDatabaseContents();
+  EXPECT_EQ(StdStringToUint8Vector("1"), contents[database_version_key_]);
+  EXPECT_EQ(StdStringToUint8Vector("0"), contents[next_map_id_key_]);
 }
 
 TEST_F(SessionStorageMetadataTest, LoadingData) {
@@ -205,16 +261,16 @@
                    ->ReferenceCount());
 
   DatabaseError error;
-  database_.Write(std::move(operations),
-                  base::BindOnce(&ErrorCallback, &error));
+  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &error));
   EXPECT_EQ(DatabaseError::OK, error);
 
   // Verify metadata was written to disk.
-  EXPECT_EQ(StdStringToUint8Vector("6"), mock_data_[next_map_id_key_]);
+  auto contents = GetDatabaseContents();
+  EXPECT_EQ(StdStringToUint8Vector("6"), contents[next_map_id_key_]);
   EXPECT_EQ(StdStringToUint8Vector("5"),
-            mock_data_[StdStringToUint8Vector(std::string("namespace-") +
-                                              test_namespace1_id_ + "-" +
-                                              test_origin1_.GetURL().spec())]);
+            contents[StdStringToUint8Vector(std::string("namespace-") +
+                                            test_namespace1_id_ + "-" +
+                                            test_origin1_.GetURL().spec())]);
 }
 
 TEST_F(SessionStorageMetadataTest, ShallowCopies) {
@@ -229,8 +285,7 @@
   metadata.RegisterShallowClonedNamespace(ns1_entry, ns3_entry, &operations);
 
   DatabaseError error;
-  database_.Write(std::move(operations),
-                  base::BindOnce(&ErrorCallback, &error));
+  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &error));
   EXPECT_EQ(DatabaseError::OK, error);
 
   // Verify in-memory metadata is correct.
@@ -246,14 +301,15 @@
   EXPECT_EQ(2, ns3_entry->second[test_origin2_]->ReferenceCount());
 
   // Verify metadata was written to disk.
+  auto contents = GetDatabaseContents();
   EXPECT_EQ(StdStringToUint8Vector("1"),
-            mock_data_[StdStringToUint8Vector(std::string("namespace-") +
-                                              test_namespace3_id_ + "-" +
-                                              test_origin1_.GetURL().spec())]);
+            contents[StdStringToUint8Vector(std::string("namespace-") +
+                                            test_namespace3_id_ + "-" +
+                                            test_origin1_.GetURL().spec())]);
   EXPECT_EQ(StdStringToUint8Vector("3"),
-            mock_data_[StdStringToUint8Vector(std::string("namespace-") +
-                                              test_namespace3_id_ + "-" +
-                                              test_origin2_.GetURL().spec())]);
+            contents[StdStringToUint8Vector(std::string("namespace-") +
+                                            test_namespace3_id_ + "-" +
+                                            test_origin2_.GetURL().spec())]);
 }
 
 TEST_F(SessionStorageMetadataTest, DeleteNamespace) {
@@ -264,8 +320,7 @@
   std::vector<leveldb::mojom::BatchedOperationPtr> operations;
   metadata.DeleteNamespace(test_namespace1_id_, &operations);
   DatabaseError error;
-  database_.Write(std::move(operations),
-                  base::BindOnce(&ErrorCallback, &error));
+  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &error));
   EXPECT_EQ(DatabaseError::OK, error);
 
   EXPECT_FALSE(
@@ -277,17 +332,17 @@
   EXPECT_EQ(1, ns2_entry->second[test_origin2_]->ReferenceCount());
 
   // Verify metadata and data was deleted from disk.
+  auto contents = GetDatabaseContents();
   EXPECT_FALSE(base::Contains(
-      mock_data_,
+      contents,
       StdStringToUint8Vector(std::string("namespace-") + test_namespace1_id_ +
                              "-" + test_origin1_.GetURL().spec())));
   EXPECT_FALSE(base::Contains(
-      mock_data_,
+      contents,
       StdStringToUint8Vector(std::string("namespace-") + test_namespace1_id_ +
                              "-" + test_origin2_.GetURL().spec())));
-  EXPECT_FALSE(
-      base::Contains(mock_data_, StdStringToUint8Vector("map-3-key1")));
-  EXPECT_TRUE(base::Contains(mock_data_, StdStringToUint8Vector("map-1-key1")));
+  EXPECT_FALSE(base::Contains(contents, StdStringToUint8Vector("map-3-key1")));
+  EXPECT_TRUE(base::Contains(contents, StdStringToUint8Vector("map-1-key1")));
 }
 
 TEST_F(SessionStorageMetadataTest, DeleteArea) {
@@ -299,8 +354,7 @@
   std::vector<leveldb::mojom::BatchedOperationPtr> operations;
   metadata.DeleteArea(test_namespace1_id_, test_origin1_, &operations);
   DatabaseError error;
-  database_.Write(std::move(operations),
-                  base::BindOnce(&ErrorCallback, &error));
+  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &error));
   EXPECT_EQ(DatabaseError::OK, error);
 
   // Verify in-memory metadata is correct.
@@ -312,22 +366,22 @@
   EXPECT_EQ(1, ns2_entry->second[test_origin2_]->ReferenceCount());
 
   // Verify only the applicable data was deleted.
+  auto contents = GetDatabaseContents();
   EXPECT_FALSE(base::Contains(
-      mock_data_,
+      contents,
       StdStringToUint8Vector(std::string("namespace-") + test_namespace1_id_ +
                              "-" + test_origin1_.GetURL().spec())));
   EXPECT_TRUE(base::Contains(
-      mock_data_,
+      contents,
       StdStringToUint8Vector(std::string("namespace-") + test_namespace1_id_ +
                              "-" + test_origin2_.GetURL().spec())));
-  EXPECT_TRUE(base::Contains(mock_data_, StdStringToUint8Vector("map-1-key1")));
-  EXPECT_TRUE(base::Contains(mock_data_, StdStringToUint8Vector("map-4-key1")));
+  EXPECT_TRUE(base::Contains(contents, StdStringToUint8Vector("map-1-key1")));
+  EXPECT_TRUE(base::Contains(contents, StdStringToUint8Vector("map-4-key1")));
 
   // Now delete an area with a unique map.
   operations.clear();
   metadata.DeleteArea(test_namespace2_id_, test_origin2_, &operations);
-  database_.Write(std::move(operations),
-                  base::BindOnce(&ErrorCallback, &error));
+  WriteBatch(std::move(operations), base::BindOnce(&ErrorCallback, &error));
   EXPECT_EQ(DatabaseError::OK, error);
 
   // Verify in-memory metadata is correct.
@@ -337,18 +391,18 @@
   EXPECT_FALSE(base::Contains(ns2_entry->second, test_origin2_));
 
   // Verify only the applicable data was deleted.
+  contents = GetDatabaseContents();
   EXPECT_TRUE(base::Contains(
-      mock_data_,
+      contents,
       StdStringToUint8Vector(std::string("namespace-") + test_namespace2_id_ +
                              "-" + test_origin1_.GetURL().spec())));
   EXPECT_FALSE(base::Contains(
-      mock_data_,
+      contents,
       StdStringToUint8Vector(std::string("namespace-") + test_namespace2_id_ +
                              "-" + test_origin2_.GetURL().spec())));
-  EXPECT_TRUE(base::Contains(mock_data_, StdStringToUint8Vector("map-1-key1")));
-  EXPECT_TRUE(base::Contains(mock_data_, StdStringToUint8Vector("map-3-key1")));
-  EXPECT_FALSE(
-      base::Contains(mock_data_, StdStringToUint8Vector("map-4-key1")));
+  EXPECT_TRUE(base::Contains(contents, StdStringToUint8Vector("map-1-key1")));
+  EXPECT_TRUE(base::Contains(contents, StdStringToUint8Vector("map-3-key1")));
+  EXPECT_FALSE(base::Contains(contents, StdStringToUint8Vector("map-4-key1")));
 }
 
 class SessionStorageMetadataMigrationTest : public testing::Test {
diff --git a/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc b/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc
index 80d4391..ed6d0b3d 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc
+++ b/content/browser/dom_storage/session_storage_namespace_impl_mojo.cc
@@ -58,7 +58,7 @@
 }
 
 void SessionStorageNamespaceImplMojo::PopulateFromMetadata(
-    leveldb::mojom::LevelDBDatabase* database,
+    leveldb::LevelDBDatabaseImpl* database,
     SessionStorageMetadata::NamespaceEntry namespace_metadata) {
   DCHECK(!IsPopulated());
   database_ = database;
@@ -85,7 +85,7 @@
 }
 
 void SessionStorageNamespaceImplMojo::PopulateAsClone(
-    leveldb::mojom::LevelDBDatabase* database,
+    leveldb::LevelDBDatabaseImpl* database,
     SessionStorageMetadata::NamespaceEntry namespace_metadata,
     const OriginAreas& areas_to_clone) {
   DCHECK(!IsPopulated());
@@ -227,7 +227,7 @@
 }
 
 void SessionStorageNamespaceImplMojo::CloneAllNamespacesWaitingForClone(
-    leveldb::mojom::LevelDBDatabase* database,
+    leveldb::LevelDBDatabaseImpl* database,
     SessionStorageMetadata* metadata,
     const std::map<std::string,
                    std::unique_ptr<SessionStorageNamespaceImplMojo>>&
diff --git a/content/browser/dom_storage/session_storage_namespace_impl_mojo.h b/content/browser/dom_storage/session_storage_namespace_impl_mojo.h
index 38f09f8..a0eb45e 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl_mojo.h
+++ b/content/browser/dom_storage/session_storage_namespace_impl_mojo.h
@@ -20,6 +20,10 @@
 #include "third_party/blink/public/mojom/dom_storage/session_storage_namespace.mojom.h"
 #include "url/origin.h"
 
+namespace leveldb {
+class LevelDBDatabaseImpl;
+}
+
 namespace content {
 
 // Implements the mojo interface SessionStorageNamespace. Stores data maps per
@@ -122,14 +126,14 @@
   // Called when this is a new namespace, or when the namespace was loaded from
   // disk. Should be called before |Bind|.
   void PopulateFromMetadata(
-      leveldb::mojom::LevelDBDatabase* database,
+      leveldb::LevelDBDatabaseImpl* database,
       SessionStorageMetadata::NamespaceEntry namespace_metadata);
 
   // Can either be called before |Bind|, or if the source namespace isn't
   // available yet, |SetWaitingForClonePopulation| can be called. Then |Bind|
   // will work, and hold onto the request until after this method is called.
   void PopulateAsClone(
-      leveldb::mojom::LevelDBDatabase* database,
+      leveldb::LevelDBDatabaseImpl* database,
       SessionStorageMetadata::NamespaceEntry namespace_metadata,
       const OriginAreas& areas_to_clone);
 
@@ -184,7 +188,7 @@
   // * If the parent is populated
   // * If the parent has a parent.
   void CloneAllNamespacesWaitingForClone(
-      leveldb::mojom::LevelDBDatabase* database,
+      leveldb::LevelDBDatabaseImpl* database,
       SessionStorageMetadata* metadata,
       const std::map<std::string,
                      std::unique_ptr<SessionStorageNamespaceImplMojo>>&
@@ -200,7 +204,7 @@
 
   const std::string namespace_id_;
   SessionStorageMetadata::NamespaceEntry namespace_entry_;
-  leveldb::mojom::LevelDBDatabase* database_ = nullptr;
+  leveldb::LevelDBDatabaseImpl* database_ = nullptr;
 
   SessionStorageDataMap::Listener* data_map_listener_;
   SessionStorageAreaImpl::RegisterNewAreaMap register_new_map_callback_;
diff --git a/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc b/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
index 1a7c84c..d9cb280f 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
+++ b/content/browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc
@@ -4,12 +4,17 @@
 
 #include "content/browser/dom_storage/session_storage_namespace_impl_mojo.h"
 
+#include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/guid.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
+#include "base/task/post_task.h"
+#include "base/test/bind_test_util.h"
+#include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/cpp/util.h"
+#include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/dom_storage/session_storage_data_map.h"
 #include "content/browser/dom_storage/session_storage_metadata.h"
@@ -17,7 +22,6 @@
 #include "content/browser/site_instance_impl.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
-#include "content/test/fake_leveldb_database.h"
 #include "content/test/gmock_util.h"
 #include "mojo/core/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
@@ -56,22 +60,46 @@
         test_namespace_id2_(base::GenerateGUID()),
         test_origin1_(url::Origin::Create(GURL("https://host1.com/"))),
         test_origin2_(url::Origin::Create(GURL("https://host2.com/"))),
-        test_origin3_(url::Origin::Create(GURL("https://host3.com/"))),
-        database_(&mock_data_) {}
+        test_origin3_(url::Origin::Create(GURL("https://host3.com/"))) {}
   ~SessionStorageNamespaceImplMojoTest() override = default;
 
+  void WriteBatch(std::vector<leveldb::mojom::BatchedOperationPtr> operations) {
+    base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed);
+    database_->Write(std::move(operations),
+                     base::BindLambdaForTesting(
+                         [&](leveldb::mojom::DatabaseError) { loop.Quit(); }));
+    loop.Run();
+  }
+
   void SetUp() override {
     // Create a database that already has a namespace saved.
+    base::RunLoop loop;
+    database_ = leveldb::LevelDBDatabaseImpl::OpenInMemory(
+        base::nullopt, "SessionStorageNamespaceImplMojoTest",
+        base::CreateSequencedTaskRunner({base::MayBlock(), base::ThreadPool()}),
+        base::BindLambdaForTesting(
+            [&](leveldb::mojom::DatabaseError) { loop.Quit(); }));
+    loop.Run();
+
     metadata_.SetupNewDatabase();
     std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
     auto entry = metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_);
     auto map_id =
         metadata_.RegisterNewMap(entry, test_origin1_, &save_operations);
     DCHECK(map_id->KeyPrefix() == StdStringToUint8Vector("map-0-"));
-    database_.Write(std::move(save_operations), base::DoNothing());
+    WriteBatch(std::move(save_operations));
+
     // Put some data in one of the maps.
-    mock_data_[StdStringToUint8Vector("map-0-key1")] =
-        StdStringToUint8Vector("data1");
+    base::RunLoop put_loop;
+    database_->database().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          ASSERT_TRUE(db.Put(StdStringToUint8Vector("map-0-key1"),
+                             StdStringToUint8Vector("data1"))
+                          .ok());
+          put_loop.Quit();
+        }));
+    put_loop.Run();
 
     auto* security_policy = ChildProcessSecurityPolicyImpl::GetInstance();
     security_policy->Add(kTestProcessIdOrigin1, &browser_context_);
@@ -127,7 +155,7 @@
     std::vector<leveldb::mojom::BatchedOperationPtr> save_operations;
     auto map_data =
         metadata_.RegisterNewMap(namespace_entry, origin, &save_operations);
-    database_.Write(std::move(save_operations), base::DoNothing());
+    WriteBatch(std::move(save_operations));
     return map_data;
   }
 
@@ -141,17 +169,18 @@
         metadata_.GetOrCreateNamespaceEntry(destination_namespace);
     metadata_.RegisterShallowClonedNamespace(source_namespace, namespace_entry,
                                              &save_operations);
-    database_.Write(std::move(save_operations), base::DoNothing());
+    WriteBatch(std::move(save_operations));
 
     auto it = namespaces_.find(destination_namespace);
     if (it == namespaces_.end()) {
       auto* namespace_impl =
           CreateSessionStorageNamespaceImplMojo(destination_namespace);
-      namespace_impl->PopulateAsClone(&database_, namespace_entry,
+      namespace_impl->PopulateAsClone(database_.get(), namespace_entry,
                                       areas_to_clone);
       return;
     }
-    it->second->PopulateAsClone(&database_, namespace_entry, areas_to_clone);
+    it->second->PopulateAsClone(database_.get(), namespace_entry,
+                                areas_to_clone);
   }
 
   scoped_refptr<SessionStorageDataMap> MaybeGetExistingDataMapForId(
@@ -179,8 +208,7 @@
       data_maps_;
 
   testing::StrictMock<MockListener> listener_;
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_;
-  FakeLevelDBDatabase database_;
+  std::unique_ptr<leveldb::LevelDBDatabaseImpl> database_;
 };
 
 TEST_F(SessionStorageNamespaceImplMojoTest, MetadataLoad) {
@@ -193,7 +221,8 @@
       .Times(1);
 
   namespace_impl->PopulateFromMetadata(
-      &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+      database_.get(),
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
 
   mojo::Remote<blink::mojom::SessionStorageNamespace> ss_namespace;
   namespace_impl->Bind(ss_namespace.BindNewPipeAndPassReceiver(),
@@ -226,7 +255,8 @@
       .Times(1);
 
   namespace_impl->PopulateFromMetadata(
-      &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+      database_.get(),
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
 
   mojo::Remote<blink::mojom::SessionStorageNamespace> ss_namespace;
   namespace_impl->Bind(ss_namespace.BindNewPipeAndPassReceiver(),
@@ -236,9 +266,13 @@
   ss_namespace->OpenArea(test_origin1_,
                          leveldb_1.BindNewEndpointAndPassReceiver());
 
-  EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK)).Times(1);
+  base::RunLoop commit_loop;
+  EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK))
+      .Times(1)
+      .WillOnce(testing::Invoke([&](auto error) { commit_loop.Quit(); }));
   test::PutSync(leveldb_1.get(), StdStringToUint8Vector("key2"),
                 StdStringToUint8Vector("data2"), base::nullopt, "");
+  commit_loop.Run();
 
   std::vector<blink::mojom::KeyValuePtr> data;
   EXPECT_TRUE(test::GetAllSync(leveldb_1.get(), &data));
@@ -252,6 +286,7 @@
 
   EXPECT_CALL(listener_, OnDataMapDestruction(StdStringToUint8Vector("0")))
       .Times(1);
+
   namespaces_.clear();
 }
 
@@ -267,7 +302,8 @@
       .Times(1);
 
   namespace_impl1->PopulateFromMetadata(
-      &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+      database_.get(),
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
 
   mojo::Remote<blink::mojom::SessionStorageNamespace> ss_namespace1;
   namespace_impl1->Bind(ss_namespace1.BindNewPipeAndPassReceiver(),
@@ -285,12 +321,18 @@
                           leveldb_2.BindNewEndpointAndPassReceiver());
 
   // Do a put in the cloned namespace.
-  EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK)).Times(2);
+  base::RunLoop commit_loop;
+  auto commit_callback = base::BarrierClosure(2, commit_loop.QuitClosure());
+  EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK))
+      .Times(2)
+      .WillRepeatedly(
+          testing::Invoke([&](auto error) { commit_callback.Run(); }));
   EXPECT_CALL(listener_,
               OnDataMapCreation(StdStringToUint8Vector("1"), testing::_))
       .Times(1);
   test::PutSync(leveldb_2.get(), StdStringToUint8Vector("key2"),
                 StdStringToUint8Vector("data2"), base::nullopt, "");
+  commit_loop.Run();
 
   std::vector<blink::mojom::KeyValuePtr> data;
   EXPECT_TRUE(test::GetAllSync(leveldb_2.get(), &data));
@@ -323,7 +365,8 @@
       .Times(1);
 
   namespace_impl1->PopulateFromMetadata(
-      &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+      database_.get(),
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
 
   mojo::Remote<blink::mojom::SessionStorageNamespace> ss_namespace1;
   namespace_impl1->Bind(ss_namespace1.BindNewPipeAndPassReceiver(),
@@ -353,9 +396,13 @@
   ASSERT_TRUE(namespace_impl2->IsPopulated());
 
   // Do a put in the cloned namespace.
-  EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK)).Times(1);
+  base::RunLoop commit_loop;
+  EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK))
+      .Times(1)
+      .WillOnce(testing::Invoke([&](auto error) { commit_loop.Quit(); }));
   test::PutSync(leveldb_n2_o2.get(), StdStringToUint8Vector("key2"),
                 StdStringToUint8Vector("data2"), base::nullopt, "");
+  commit_loop.Run();
 
   std::vector<blink::mojom::KeyValuePtr> data;
   EXPECT_TRUE(test::GetAllSync(leveldb_n2_o1.get(), &data));
@@ -387,7 +434,8 @@
       .Times(1);
 
   namespace_impl->PopulateFromMetadata(
-      &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+      database_.get(),
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
 
   mojo::Remote<blink::mojom::SessionStorageNamespace> ss_namespace;
   namespace_impl->Bind(ss_namespace.BindNewPipeAndPassReceiver(),
@@ -409,8 +457,12 @@
   EXPECT_CALL(mock_observer, AllDeleted("\n"))
       .WillOnce(base::test::RunClosure(loop.QuitClosure()));
 
-  EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK)).Times(1);
+  base::RunLoop commit_loop;
+  EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK))
+      .Times(1)
+      .WillOnce(testing::Invoke([&](auto error) { commit_loop.Quit(); }));
   namespace_impl->RemoveOriginData(test_origin1_, base::DoNothing());
+  commit_loop.Run();
 
   std::vector<blink::mojom::KeyValuePtr> data;
   EXPECT_TRUE(test::GetAllSync(leveldb_1.get(), &data));
@@ -433,7 +485,8 @@
       .Times(1);
 
   namespace_impl->PopulateFromMetadata(
-      &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+      database_.get(),
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
 
   base::RunLoop loop;
   EXPECT_CALL(listener_, OnCommitResult(DatabaseError::OK))
@@ -457,7 +510,8 @@
       .Times(1);
 
   namespace_impl->PopulateFromMetadata(
-      &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+      database_.get(),
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
 
   mojo::Remote<blink::mojom::SessionStorageNamespace> ss_namespace;
   namespace_impl->Bind(ss_namespace.BindNewPipeAndPassReceiver(),
@@ -484,7 +538,8 @@
       .Times(1);
 
   namespace_impl->PopulateFromMetadata(
-      &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+      database_.get(),
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
 
   mojo::Remote<blink::mojom::SessionStorageNamespace> ss_namespace;
   namespace_impl->Bind(ss_namespace.BindNewPipeAndPassReceiver(),
@@ -517,7 +572,8 @@
       .Times(1);
 
   namespace_impl->PopulateFromMetadata(
-      &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+      database_.get(),
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
 
   mojo::Remote<blink::mojom::SessionStorageNamespace> ss_namespace_o1;
   namespace_impl->Bind(ss_namespace_o1.BindNewPipeAndPassReceiver(),
@@ -561,7 +617,8 @@
       .WillOnce(testing::SaveArg<1>(&data_map));
 
   namespace_impl->PopulateFromMetadata(
-      &database_, metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
+      database_.get(),
+      metadata_.GetOrCreateNamespaceEntry(test_namespace_id1_));
 
   mojo::Remote<blink::mojom::SessionStorageNamespace> ss_namespace;
   namespace_impl->Bind(ss_namespace.BindNewPipeAndPassReceiver(),
diff --git a/content/browser/dom_storage/storage_area_impl.cc b/content/browser/dom_storage/storage_area_impl.cc
index 7b3ceec..e405b01 100644
--- a/content/browser/dom_storage/storage_area_impl.cc
+++ b/content/browser/dom_storage/storage_area_impl.cc
@@ -10,6 +10,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/process_memory_dump.h"
+#include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/cpp/util.h"
 #include "content/public/browser/browser_thread.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
@@ -58,7 +59,7 @@
 StorageAreaImpl::CommitBatch::CommitBatch() : clear_all_first(false) {}
 StorageAreaImpl::CommitBatch::~CommitBatch() {}
 
-StorageAreaImpl::StorageAreaImpl(leveldb::mojom::LevelDBDatabase* database,
+StorageAreaImpl::StorageAreaImpl(leveldb::LevelDBDatabaseImpl* database,
                                  const std::string& prefix,
                                  Delegate* delegate,
                                  const Options& options)
@@ -67,7 +68,7 @@
                       delegate,
                       options) {}
 
-StorageAreaImpl::StorageAreaImpl(leveldb::mojom::LevelDBDatabase* database,
+StorageAreaImpl::StorageAreaImpl(leveldb::LevelDBDatabaseImpl* database,
                                  std::vector<uint8_t> prefix,
                                  Delegate* delegate,
                                  const Options& options)
diff --git a/content/browser/dom_storage/storage_area_impl.h b/content/browser/dom_storage/storage_area_impl.h
index 5a54c6b..28bc039 100644
--- a/content/browser/dom_storage/storage_area_impl.h
+++ b/content/browser/dom_storage/storage_area_impl.h
@@ -29,11 +29,15 @@
 }
 }  // namespace base
 
+namespace leveldb {
+class LevelDBDatabaseImpl;
+}
+
 namespace content {
 
-// This is a wrapper around a leveldb::mojom::LevelDBDatabase. Multiple
-// interface pointers can be bound to the same object. The wrapper adds a couple
-// of features not found directly in leveldb.
+// This is a wrapper around a leveldb::LevelDBDatabaseImpl. Multiple interface
+// endpoints can be bound to the same object. The wrapper adds a couple of
+// features not found directly in leveldb:
 // 1) Adds the given prefix, if any, to all keys. This allows the sharing of one
 //    database across many, possibly untrusted, consumers and ensuring that they
 //    can't access each other's values.
@@ -91,11 +95,11 @@
 
   // |Delegate::OnNoBindings| will be called when this object has no more
   // bindings and all pending modifications have been processed.
-  StorageAreaImpl(leveldb::mojom::LevelDBDatabase* database,
+  StorageAreaImpl(leveldb::LevelDBDatabaseImpl* database,
                   const std::string& prefix,
                   Delegate* delegate,
                   const Options& options);
-  StorageAreaImpl(leveldb::mojom::LevelDBDatabase* database,
+  StorageAreaImpl(leveldb::LevelDBDatabaseImpl* database,
                   std::vector<uint8_t> prefix,
                   Delegate* delegate,
                   const Options& options);
@@ -152,7 +156,7 @@
 
   const std::vector<uint8_t>& prefix() { return prefix_; }
 
-  leveldb::mojom::LevelDBDatabase* database() { return database_; }
+  leveldb::LevelDBDatabaseImpl* database() { return database_; }
 
   // Commence aggressive flushing. This should be called early during startup,
   // before any localStorage writing. Currently scheduled writes will not be
@@ -322,7 +326,7 @@
   mojo::ReceiverSet<blink::mojom::StorageArea> receivers_;
   mojo::AssociatedRemoteSet<blink::mojom::StorageAreaObserver> observers_;
   Delegate* delegate_;
-  leveldb::mojom::LevelDBDatabase* database_;
+  leveldb::LevelDBDatabaseImpl* database_;
 
   // For commits to work correctly the map loaded state (keys vs keys & values)
   // must stay consistent for a given commit batch.
diff --git a/content/browser/dom_storage/storage_area_impl_unittest.cc b/content/browser/dom_storage/storage_area_impl_unittest.cc
index ad799f95..963db65 100644
--- a/content/browser/dom_storage/storage_area_impl_unittest.cc
+++ b/content/browser/dom_storage/storage_area_impl_unittest.cc
@@ -7,19 +7,22 @@
 #include "base/atomic_ref_count.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/containers/span.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task_runner_util.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread.h"
+#include "components/services/leveldb/leveldb_database_impl.h"
 #include "components/services/leveldb/public/cpp/util.h"
 #include "components/services/leveldb/public/mojom/leveldb.mojom.h"
+#include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/test/storage_area_test_util.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/test/barrier_builder.h"
-#include "content/test/fake_leveldb_database.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -40,8 +43,8 @@
   return leveldb::Uint8VectorToStdString(input);
 }
 
-std::vector<uint8_t> ToBytes(const std::string& input) {
-  return leveldb::StdStringToUint8Vector(input);
+std::vector<uint8_t> ToBytes(base::StringPiece input) {
+  return std::vector<uint8_t>(input.begin(), input.end());
 }
 
 class MockDelegate : public StorageAreaImpl::Delegate {
@@ -122,41 +125,86 @@
     bool should_send_old_value;
   };
 
-  StorageAreaImplTest() : db_(&mock_data_) {
+  StorageAreaImplTest() {
+    base::RunLoop loop;
+    db_ = leveldb::LevelDBDatabaseImpl::OpenInMemory(
+        base::nullopt, "StorageAreaImplTest",
+        base::CreateSequencedTaskRunner({base::MayBlock(), base::ThreadPool()}),
+        base::BindLambdaForTesting(
+            [&](leveldb::mojom::DatabaseError error) { loop.Quit(); }));
+    loop.Run();
+
     StorageAreaImpl::Options options =
         GetDefaultTestingOptions(CacheMode::KEYS_ONLY_WHEN_POSSIBLE);
-    storage_area_ = std::make_unique<StorageAreaImpl>(&db_, test_prefix_,
+    storage_area_ = std::make_unique<StorageAreaImpl>(db_.get(), test_prefix_,
                                                       &delegate_, options);
 
-    set_mock_data(test_prefix_ + test_key1_, test_value1_);
-    set_mock_data(test_prefix_ + test_key2_, test_value2_);
-    set_mock_data("123", "baddata");
+    SetDatabaseEntry(test_prefix_ + test_key1_, test_value1_);
+    SetDatabaseEntry(test_prefix_ + test_key2_, test_value2_);
+    SetDatabaseEntry("123", "baddata");
 
     storage_area_->Bind(storage_area_remote_.BindNewPipeAndPassReceiver());
     storage_area_remote_->AddObserver(
         observer_receiver_.BindNewEndpointAndPassRemote());
   }
 
-  ~StorageAreaImplTest() override {}
+  ~StorageAreaImplTest() override = default;
 
-  void set_mock_data(const std::string& key, const std::string& value) {
-    mock_data_[ToBytes(key)] = ToBytes(value);
+  void SetDatabaseEntry(const std::vector<uint8_t>& key,
+                        const std::vector<uint8_t>& value) {
+    base::RunLoop loop;
+    db_->database().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          ASSERT_TRUE(db.Put(key, value).ok());
+          loop.Quit();
+        }));
+    loop.Run();
   }
 
-  void set_mock_data(const std::vector<uint8_t>& key,
-                     const std::vector<uint8_t>& value) {
-    mock_data_[key] = value;
+  void SetDatabaseEntry(base::StringPiece key, base::StringPiece value) {
+    SetDatabaseEntry(ToBytes(key), ToBytes(value));
   }
 
-  bool has_mock_data(const std::string& key) {
-    return mock_data_.find(ToBytes(key)) != mock_data_.end();
+  std::string GetDatabaseEntry(base::StringPiece key) {
+    std::vector<uint8_t> value;
+    base::RunLoop loop;
+    db_->database().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          ASSERT_TRUE(db.Get(ToBytes(key), &value).ok());
+          loop.Quit();
+        }));
+    loop.Run();
+    return std::string(value.begin(), value.end());
   }
 
-  std::string get_mock_data(const std::string& key) {
-    return has_mock_data(key) ? ToString(mock_data_[ToBytes(key)]) : "";
+  bool HasDatabaseEntry(base::StringPiece key) {
+    base::RunLoop loop;
+    leveldb::Status status;
+    db_->database().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          std::vector<uint8_t> value;
+          status = db.Get(ToBytes(key), &value);
+          loop.Quit();
+        }));
+    loop.Run();
+    return status.ok();
   }
 
-  void clear_mock_data() { mock_data_.clear(); }
+  void ClearDatabase() {
+    base::RunLoop loop;
+    db_->database().PostTaskWithThisObject(
+        FROM_HERE,
+        base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
+          leveldb::WriteBatch batch;
+          ASSERT_TRUE(db.DeletePrefixed({}, &batch).ok());
+          ASSERT_TRUE(db.Commit(&batch).ok());
+          loop.Quit();
+        }));
+    loop.Run();
+  }
 
   blink::mojom::StorageArea* storage_area() {
     return storage_area_remote_.get();
@@ -235,7 +283,7 @@
   const std::vector<Observation>& observations() { return observations_; }
 
   MockDelegate* delegate() { return &delegate_; }
-  leveldb::mojom::LevelDBDatabase* database() { return &db_; }
+  leveldb::LevelDBDatabaseImpl* database() { return db_.get(); }
 
   void should_record_send_old_value_observations(bool value) {
     should_record_send_old_value_observations_ = value;
@@ -291,8 +339,7 @@
   }
 
   BrowserTaskEnvironment task_environment_;
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_;
-  FakeLevelDBDatabase db_;
+  std::unique_ptr<leveldb::LevelDBDatabaseImpl> db_;
   MockDelegate delegate_;
   std::unique_ptr<StorageAreaImpl> storage_area_;
   mojo::Remote<blink::mojom::StorageArea> storage_area_remote_;
@@ -437,13 +484,13 @@
   EXPECT_TRUE(put_success2);
   EXPECT_TRUE(put_success3);
 
-  EXPECT_FALSE(has_mock_data(test_prefix_ + key2));
+  EXPECT_FALSE(HasDatabaseEntry(test_prefix_ + key2));
 
   BlockingCommit();
-  EXPECT_TRUE(has_mock_data(test_prefix_ + key1));
-  EXPECT_EQ(value1, get_mock_data(test_prefix_ + key1));
-  EXPECT_TRUE(has_mock_data(test_prefix_ + key2));
-  EXPECT_EQ(value2, get_mock_data(test_prefix_ + key2));
+  EXPECT_TRUE(HasDatabaseEntry(test_prefix_ + key1));
+  EXPECT_EQ(value1, GetDatabaseEntry(test_prefix_ + key1));
+  EXPECT_TRUE(HasDatabaseEntry(test_prefix_ + key2));
+  EXPECT_EQ(value2, GetDatabaseEntry(test_prefix_ + key2));
 }
 
 TEST_P(StorageAreaImplParamTest, PutObservations) {
@@ -484,7 +531,7 @@
   storage_area_impl()->SetCacheModeForTesting(GetParam());
   std::string key = "newkey";
   std::string value = "foo";
-  set_mock_data(test_prefix_ + key, value);
+  SetDatabaseEntry(test_prefix_ + key, value);
 
   EXPECT_TRUE(DeleteSync(ToBytes(key), ToBytes(value)));
   ASSERT_EQ(1u, observations().size());
@@ -493,10 +540,10 @@
   EXPECT_EQ(value, observations()[0].old_value);
   EXPECT_EQ(test_source_, observations()[0].source);
 
-  EXPECT_TRUE(has_mock_data(test_prefix_ + key));
+  EXPECT_TRUE(HasDatabaseEntry(test_prefix_ + key));
 
   BlockingCommit();
-  EXPECT_FALSE(has_mock_data(test_prefix_ + key));
+  EXPECT_FALSE(HasDatabaseEntry(test_prefix_ + key));
 }
 
 TEST_P(StorageAreaImplParamTest, DeleteAllWithoutLoadedMap) {
@@ -504,20 +551,20 @@
   std::string key = "newkey";
   std::string value = "foo";
   std::string dummy_key = "foobar";
-  set_mock_data(dummy_key, value);
-  set_mock_data(test_prefix_ + key, value);
+  SetDatabaseEntry(dummy_key, value);
+  SetDatabaseEntry(test_prefix_ + key, value);
 
   EXPECT_TRUE(DeleteAllSync());
   ASSERT_EQ(1u, observations().size());
   EXPECT_EQ(Observation::kDeleteAll, observations()[0].type);
   EXPECT_EQ(test_source_, observations()[0].source);
 
-  EXPECT_TRUE(has_mock_data(test_prefix_ + key));
-  EXPECT_TRUE(has_mock_data(dummy_key));
+  EXPECT_TRUE(HasDatabaseEntry(test_prefix_ + key));
+  EXPECT_TRUE(HasDatabaseEntry(dummy_key));
 
   BlockingCommit();
-  EXPECT_FALSE(has_mock_data(test_prefix_ + key));
-  EXPECT_TRUE(has_mock_data(dummy_key));
+  EXPECT_FALSE(HasDatabaseEntry(test_prefix_ + key));
+  EXPECT_TRUE(HasDatabaseEntry(dummy_key));
 
   // Deleting all again should still work, but not cause an observation.
   EXPECT_TRUE(DeleteAllSync());
@@ -533,7 +580,7 @@
   std::string key = "newkey";
   std::string value = "foo";
   std::string dummy_key = "foobar";
-  set_mock_data(dummy_key, value);
+  SetDatabaseEntry(dummy_key, value);
 
   EXPECT_TRUE(PutSync(ToBytes(key), ToBytes(value), base::nullopt));
 
@@ -542,11 +589,11 @@
   EXPECT_EQ(Observation::kDeleteAll, observations()[1].type);
   EXPECT_EQ(test_source_, observations()[1].source);
 
-  EXPECT_TRUE(has_mock_data(dummy_key));
+  EXPECT_TRUE(HasDatabaseEntry(dummy_key));
 
   BlockingCommit();
-  EXPECT_FALSE(has_mock_data(test_prefix_ + key));
-  EXPECT_TRUE(has_mock_data(dummy_key));
+  EXPECT_FALSE(HasDatabaseEntry(test_prefix_ + key));
+  EXPECT_TRUE(HasDatabaseEntry(dummy_key));
 }
 
 TEST_P(StorageAreaImplParamTest, DeleteAllWithPendingMapLoad) {
@@ -554,7 +601,7 @@
   std::string key = "newkey";
   std::string value = "foo";
   std::string dummy_key = "foobar";
-  set_mock_data(dummy_key, value);
+  SetDatabaseEntry(dummy_key, value);
 
   storage_area()->Put(ToBytes(key), ToBytes(value), base::nullopt, kTestSource,
                       base::DoNothing());
@@ -564,16 +611,16 @@
   EXPECT_EQ(Observation::kDeleteAll, observations()[1].type);
   EXPECT_EQ(test_source_, observations()[1].source);
 
-  EXPECT_TRUE(has_mock_data(dummy_key));
+  EXPECT_TRUE(HasDatabaseEntry(dummy_key));
 
   BlockingCommit();
-  EXPECT_FALSE(has_mock_data(test_prefix_ + key));
-  EXPECT_TRUE(has_mock_data(dummy_key));
+  EXPECT_FALSE(HasDatabaseEntry(test_prefix_ + key));
+  EXPECT_TRUE(HasDatabaseEntry(dummy_key));
 }
 
 TEST_P(StorageAreaImplParamTest, DeleteAllWithoutLoadedEmptyMap) {
   storage_area_impl()->SetCacheModeForTesting(GetParam());
-  clear_mock_data();
+  ClearDatabase();
 
   EXPECT_TRUE(DeleteAllSync());
   ASSERT_EQ(0u, observations().size());
@@ -607,7 +654,7 @@
   std::vector<uint8_t> value(kTestSizeLimit, 4);
   std::vector<uint8_t> old_value = value;
 
-  set_mock_data(test_prefix_ + key, ToString(value));
+  SetDatabaseEntry(test_prefix_ + key, ToString(value));
 
   // Put with same data should succeed.
   EXPECT_TRUE(PutSync(ToBytes(key), value, base::nullopt));
@@ -641,7 +688,7 @@
   std::vector<uint8_t> value = ToBytes("value");
   std::vector<uint8_t> old_value = value;
 
-  set_mock_data(test_prefix_ + ToString(key), ToString(value));
+  SetDatabaseEntry(test_prefix_ + ToString(key), ToString(value));
 
   // Put with same data size should succeed.
   value[0] = 'X';
@@ -709,9 +756,9 @@
   EXPECT_EQ(test_key1_, ToString(data[1]->key));
   EXPECT_EQ("foo", ToString(data[1]->value));
 
-  EXPECT_FALSE(has_mock_data(test_prefix_ + test_key2_));
-  EXPECT_EQ("foo", get_mock_data(test_prefix_ + test_key1_));
-  EXPECT_EQ("bla", get_mock_data(test_prefix_ + test_prefix_));
+  EXPECT_FALSE(HasDatabaseEntry(test_prefix_ + test_key2_));
+  EXPECT_EQ("foo", GetDatabaseEntry(test_prefix_ + test_key1_));
+  EXPECT_EQ("bla", GetDatabaseEntry(test_prefix_ + test_prefix_));
 }
 
 TEST_F(StorageAreaImplTest, SetOnlyKeysWithoutDatabase) {
@@ -792,7 +839,7 @@
 
   BlockingCommit();
 
-  EXPECT_EQ("foo2", get_mock_data(test_prefix_ + test_key2_));
+  EXPECT_EQ("foo2", GetDatabaseEntry(test_prefix_ + test_key2_));
   if (GetParam() == CacheMode::KEYS_AND_VALUES)
     EXPECT_EQ(2u, storage_area_impl()->keys_values_map_.size());
   else
@@ -815,10 +862,10 @@
     EXPECT_EQ(value3, it->second);
   }
 
-  clear_mock_data();
+  ClearDatabase();
   EXPECT_TRUE(storage_area_impl()->has_changes_to_commit());
   BlockingCommit();
-  EXPECT_EQ("foobar", get_mock_data(test_prefix_ + test_key2_));
+  EXPECT_EQ("foobar", GetDatabaseEntry(test_prefix_ + test_key2_));
   EXPECT_FALSE(storage_area_impl()->has_changes_to_commit());
 }
 
@@ -838,7 +885,6 @@
   bool result = false;
 
   base::RunLoop loop;
-
   bool put_result1 = false;
   bool put_result2 = false;
   {
@@ -859,7 +905,7 @@
 
   // GetAll triggers a commit when it's switching map types.
   EXPECT_TRUE(put_result1);
-  EXPECT_EQ("foo", get_mock_data(test_prefix_ + test_key2_));
+  EXPECT_EQ("foo", GetDatabaseEntry(test_prefix_ + test_key2_));
 
   loop.Run();
 
@@ -876,12 +922,12 @@
   EXPECT_TRUE(get_all_success);
 
   // The last "put" isn't committed yet.
-  EXPECT_EQ("foo", get_mock_data(test_prefix_ + test_key2_));
+  EXPECT_EQ("foo", GetDatabaseEntry(test_prefix_ + test_key2_));
 
   ASSERT_TRUE(storage_area_impl()->has_changes_to_commit());
   BlockingCommit();
 
-  EXPECT_EQ("foobar", get_mock_data(test_prefix_ + test_key2_));
+  EXPECT_EQ("foobar", GetDatabaseEntry(test_prefix_ + test_key2_));
 }
 
 TEST_F(StorageAreaImplTest, GetAllAfterSetCacheMode) {
@@ -948,12 +994,12 @@
 
   // GetAll shouldn't trigger a commit before it runs now because the value
   // map should be loading.
-  EXPECT_EQ("foobar", get_mock_data(test_prefix_ + test_key2_));
+  EXPECT_EQ("foobar", GetDatabaseEntry(test_prefix_ + test_key2_));
 
   ASSERT_TRUE(storage_area_impl()->has_changes_to_commit());
   BlockingCommit();
 
-  EXPECT_FALSE(has_mock_data(test_prefix_ + test_key2_));
+  EXPECT_FALSE(HasDatabaseEntry(test_prefix_ + test_key2_));
 }
 
 TEST_F(StorageAreaImplTest, SetCacheModeConsistent) {
@@ -966,7 +1012,7 @@
               CacheMode::KEYS_ONLY_WHEN_POSSIBLE);
 
   // Clear the database before the area loads data.
-  clear_mock_data();
+  ClearDatabase();
 
   EXPECT_TRUE(PutSync(key, value, base::nullopt));
   EXPECT_TRUE(storage_area_impl()->has_changes_to_commit());
@@ -1106,16 +1152,16 @@
   BlockingCommit(&fork1_delegate, fork1.get());
 
   // test_key1_ values.
-  EXPECT_EQ(value3, get_mock_data(test_prefix_ + test_key1_));
-  EXPECT_EQ(test_value1_, get_mock_data(test_copy_prefix1_ + test_key1_));
-  EXPECT_EQ(test_value1_, get_mock_data(test_copy_prefix2_ + test_key1_));
-  EXPECT_EQ(value3, get_mock_data(test_copy_prefix3_ + test_key1_));
+  EXPECT_EQ(value3, GetDatabaseEntry(test_prefix_ + test_key1_));
+  EXPECT_EQ(test_value1_, GetDatabaseEntry(test_copy_prefix1_ + test_key1_));
+  EXPECT_EQ(test_value1_, GetDatabaseEntry(test_copy_prefix2_ + test_key1_));
+  EXPECT_EQ(value3, GetDatabaseEntry(test_copy_prefix3_ + test_key1_));
 
   // test_key2_ values.
-  EXPECT_EQ(test_value2_, get_mock_data(test_prefix_ + test_key2_));
-  EXPECT_EQ(value5, get_mock_data(test_copy_prefix1_ + test_key2_));
-  EXPECT_EQ(value4, get_mock_data(test_copy_prefix2_ + test_key2_));
-  EXPECT_EQ(test_value2_, get_mock_data(test_copy_prefix3_ + test_key2_));
+  EXPECT_EQ(test_value2_, GetDatabaseEntry(test_prefix_ + test_key2_));
+  EXPECT_EQ(value5, GetDatabaseEntry(test_copy_prefix1_ + test_key2_));
+  EXPECT_EQ(value4, GetDatabaseEntry(test_copy_prefix2_ + test_key2_));
+  EXPECT_EQ(test_value2_, GetDatabaseEntry(test_copy_prefix3_ + test_key2_));
 }
 
 TEST_P(StorageAreaImplParamTest, PrefixForkAfterLoad) {
@@ -1136,7 +1182,7 @@
 
   BlockingCommit(delegate(), storage_area_impl());
 
-  EXPECT_EQ(kValue, get_mock_data(test_copy_prefix1_ + test_key1_));
+  EXPECT_EQ(kValue, GetDatabaseEntry(test_copy_prefix1_ + test_key1_));
 }
 
 namespace {
@@ -1280,12 +1326,12 @@
     std::vector<uint8_t> prefix = areas[i]->prefix();
     std::string key1 = ToString(prefix) + kKey1;
     std::string key2 = ToString(prefix) + kKey2;
-    EXPECT_EQ(!!state.val1, has_mock_data(key1));
+    EXPECT_EQ(!!state.val1, HasDatabaseEntry(key1));
     if (state.val1)
-      EXPECT_EQ(ToString(state.val1.value()), get_mock_data(key1));
-    EXPECT_EQ(!!state.val2, has_mock_data(key2));
+      EXPECT_EQ(ToString(state.val1.value()), GetDatabaseEntry(key1));
+    EXPECT_EQ(!!state.val2, HasDatabaseEntry(key2));
     if (state.val2)
-      EXPECT_EQ(ToString(state.val2.value()), get_mock_data(key2));
+      EXPECT_EQ(ToString(state.val2.value()), GetDatabaseEntry(key2));
 
     EXPECT_FALSE(areas[i]->has_pending_load_tasks()) << i;
   }
@@ -1296,7 +1342,7 @@
   const std::vector<uint8_t> kValueVec = ToBytes(kValue);
 
   // Set fake data to ensure that our shortcut doesn't read it.
-  set_mock_data(test_copy_prefix1_ + test_key1_, kValue);
+  SetDatabaseEntry(test_copy_prefix1_ + test_key1_, kValue);
 
   // Create an empty map that will have no data in it.
   StorageAreaImpl::Options options =
@@ -1314,7 +1360,7 @@
   const std::vector<uint8_t> kValueVec = ToBytes(kValue);
 
   // Set fake data to ensure that our shortcut doesn't read it.
-  set_mock_data(test_copy_prefix1_ + test_key1_, kValue);
+  SetDatabaseEntry(test_copy_prefix1_ + test_key1_, kValue);
 
   // Create an empty map that will have no data in it.
   StorageAreaImpl::Options options =
diff --git a/content/browser/dom_storage/test/fake_leveldb_database_error_on_write.cc b/content/browser/dom_storage/test/fake_leveldb_database_error_on_write.cc
deleted file mode 100644
index c4a8be9..0000000
--- a/content/browser/dom_storage/test/fake_leveldb_database_error_on_write.cc
+++ /dev/null
@@ -1,28 +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 "content/browser/dom_storage/test/fake_leveldb_database_error_on_write.h"
-
-#include "base/callback.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-
-namespace content {
-namespace test {
-
-FakeLevelDBDatabaseErrorOnWrite::FakeLevelDBDatabaseErrorOnWrite(
-    std::map<std::vector<uint8_t>, std::vector<uint8_t>>* mock_data)
-    : FakeLevelDBDatabase(mock_data) {}
-
-FakeLevelDBDatabaseErrorOnWrite::~FakeLevelDBDatabaseErrorOnWrite() = default;
-
-void FakeLevelDBDatabaseErrorOnWrite::Write(
-    std::vector<leveldb::mojom::BatchedOperationPtr> operations,
-    WriteCallback callback) {
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback),
-                                leveldb::mojom::DatabaseError::IO_ERROR));
-}
-
-}  // namespace test
-}  // namespace content
diff --git a/content/browser/dom_storage/test/fake_leveldb_database_error_on_write.h b/content/browser/dom_storage/test/fake_leveldb_database_error_on_write.h
deleted file mode 100644
index 2bda2ba..0000000
--- a/content/browser/dom_storage/test/fake_leveldb_database_error_on_write.h
+++ /dev/null
@@ -1,31 +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_BROWSER_DOM_STORAGE_TEST_FAKE_LEVELDB_DATABASE_ERROR_ON_WRITE_H_
-#define CONTENT_BROWSER_DOM_STORAGE_TEST_FAKE_LEVELDB_DATABASE_ERROR_ON_WRITE_H_
-
-#include <stdint.h>
-#include <map>
-#include <vector>
-
-#include "content/test/fake_leveldb_database.h"
-
-namespace content {
-namespace test {
-
-// Reports an error on every |Write| call.
-class FakeLevelDBDatabaseErrorOnWrite : public FakeLevelDBDatabase {
- public:
-  explicit FakeLevelDBDatabaseErrorOnWrite(
-      std::map<std::vector<uint8_t>, std::vector<uint8_t>>* mock_data);
-  ~FakeLevelDBDatabaseErrorOnWrite() override;
-
-  void Write(std::vector<leveldb::mojom::BatchedOperationPtr> operations,
-             WriteCallback callback) override;
-};
-
-}  // namespace test
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_DOM_STORAGE_TEST_FAKE_LEVELDB_DATABASE_ERROR_ON_WRITE_H_
diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h
index e786d48..ebba4a6b 100644
--- a/content/browser/frame_host/render_frame_host_delegate.h
+++ b/content/browser/frame_host/render_frame_host_delegate.h
@@ -210,11 +210,6 @@
                            const base::string16& title,
                            base::i18n::TextDirection title_direction) {}
 
-  // The page's encoding was changed and should be updated. Only called for the
-  // top-level frame.
-  virtual void UpdateEncoding(RenderFrameHost* render_frame_host,
-                              const std::string& encoding) {}
-
   // Return this object cast to a WebContents, if it is one. If the object is
   // not a WebContents, returns NULL.
   virtual WebContents* GetAsWebContents();
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 1e8c682..df23041 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -16,6 +16,7 @@
 #include "base/debug/alias.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/hash/hash.h"
+#include "base/i18n/character_encoding.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
@@ -1304,13 +1305,15 @@
       std::move(default_factory_request));
 }
 
-void RenderFrameHostImpl::MarkInitiatorsAsRequiringSeparateURLLoaderFactory(
-    base::flat_set<url::Origin> request_initiators,
+void RenderFrameHostImpl::MarkIsolatedWorldsAsRequiringSeparateURLLoaderFactory(
+    base::flat_set<url::Origin> isolated_world_origins,
     bool push_to_renderer_now) {
-  size_t old_size = initiators_requiring_separate_url_loader_factory_.size();
-  initiators_requiring_separate_url_loader_factory_.insert(
-      request_initiators.begin(), request_initiators.end());
-  size_t new_size = initiators_requiring_separate_url_loader_factory_.size();
+  size_t old_size =
+      isolated_worlds_requiring_separate_url_loader_factory_.size();
+  isolated_worlds_requiring_separate_url_loader_factory_.insert(
+      isolated_world_origins.begin(), isolated_world_origins.end());
+  size_t new_size =
+      isolated_worlds_requiring_separate_url_loader_factory_.size();
   bool insertion_took_place = (old_size != new_size);
 
   // Push the updated set of factories to the renderer, but only if
@@ -1327,8 +1330,8 @@
     std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
         subresource_loader_factories =
             std::make_unique<blink::URLLoaderFactoryBundleInfo>();
-    subresource_loader_factories->pending_initiator_specific_factories() =
-        CreateInitiatorSpecificURLLoaderFactories(request_initiators);
+    subresource_loader_factories->pending_isolated_world_factories() =
+        CreateURLLoaderFactoriesForIsolatedWorlds(isolated_world_origins);
     GetNavigationControl()->UpdateSubresourceLoaderFactories(
         std::move(subresource_loader_factories));
   }
@@ -1345,10 +1348,10 @@
 }
 
 blink::URLLoaderFactoryBundleInfo::OriginMap
-RenderFrameHostImpl::CreateInitiatorSpecificURLLoaderFactories(
-    const base::flat_set<url::Origin>& initiator_origins) {
+RenderFrameHostImpl::CreateURLLoaderFactoriesForIsolatedWorlds(
+    const base::flat_set<url::Origin>& isolated_world_origins) {
   blink::URLLoaderFactoryBundleInfo::OriginMap result;
-  for (const url::Origin& initiator : initiator_origins) {
+  for (const url::Origin& initiator : isolated_world_origins) {
     network::mojom::URLLoaderFactoryPtrInfo factory_info;
     CreateNetworkServiceDefaultFactoryAndObserve(
         initiator, network_isolation_key_, mojo::MakeRequest(&factory_info));
@@ -3164,8 +3167,8 @@
           std::make_unique<blink::URLLoaderFactoryBundleInfo>(
               std::move(default_factory_info),
               blink::URLLoaderFactoryBundleInfo::SchemeMap(),
-              CreateInitiatorSpecificURLLoaderFactories(
-                  initiators_requiring_separate_url_loader_factory_),
+              CreateURLLoaderFactoriesForIsolatedWorlds(
+                  isolated_worlds_requiring_separate_url_loader_factory_),
               bypass_redirect_checks);
   GetNavigationControl()->UpdateSubresourceLoaderFactories(
       std::move(subresource_loader_factories));
@@ -3327,7 +3330,12 @@
 void RenderFrameHostImpl::UpdateEncoding(const std::string& encoding_name) {
   // This message is only sent for top-level frames. TODO(avi): when frame tree
   // mirroring works correctly, add a check here to enforce it.
-  delegate_->UpdateEncoding(this, encoding_name);
+  if (encoding_name == last_reported_encoding_)
+    return;
+  last_reported_encoding_ = encoding_name;
+
+  canonical_encoding_ =
+      base::GetCanonicalEncodingNameByAliasName(encoding_name);
 }
 
 void RenderFrameHostImpl::FrameSizeChanged(const gfx::Size& frame_size) {
@@ -3517,6 +3525,16 @@
     frame_->UpdateBrowserControlsState(constraints, current, animate);
 }
 
+void RenderFrameHostImpl::Reload() {
+  if (!IsRenderFrameLive())
+    return;
+
+  // TODO(https://crbug.com/995428). This IPC is deprecated. Navigations are
+  // handled from the browser process. There is no need to send an IPC to the
+  // renderer process for this.
+  Send(new FrameMsg_Reload(GetRoutingID()));
+}
+
 void RenderFrameHostImpl::SendAccessibilityEventsToManager(
     const AXEventNotificationDetails& details) {
   if (browser_accessibility_manager_ &&
@@ -4109,8 +4127,8 @@
   return std::make_unique<blink::URLLoaderFactoryBundleInfo>(
       std::move(pending_default_factory),
       blink::URLLoaderFactoryBundleInfo::SchemeMap(),
-      CreateInitiatorSpecificURLLoaderFactories(
-          initiators_requiring_separate_url_loader_factory_),
+      CreateURLLoaderFactoriesForIsolatedWorlds(
+          isolated_worlds_requiring_separate_url_loader_factory_),
       bypass_redirect_checks);
 }
 
@@ -5352,9 +5370,9 @@
           factory.first, std::move(pending_factory_proxy));
     }
 
-    subresource_loader_factories->pending_initiator_specific_factories() =
-        CreateInitiatorSpecificURLLoaderFactories(
-            initiators_requiring_separate_url_loader_factory_);
+    subresource_loader_factories->pending_isolated_world_factories() =
+        CreateURLLoaderFactoriesForIsolatedWorlds(
+            isolated_worlds_requiring_separate_url_loader_factory_);
   }
 
   // It is imperative that cross-document navigations always provide a set of
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 2064083..7827f67 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -300,8 +300,8 @@
       const blink::WebMediaPlayerAction& action) override;
   bool CreateNetworkServiceDefaultFactory(
       network::mojom::URLLoaderFactoryRequest default_factory_request) override;
-  void MarkInitiatorsAsRequiringSeparateURLLoaderFactory(
-      base::flat_set<url::Origin> request_initiators,
+  void MarkIsolatedWorldsAsRequiringSeparateURLLoaderFactory(
+      base::flat_set<url::Origin> isolated_world_origins,
       bool push_to_renderer_now) override;
   bool IsSandboxed(blink::WebSandboxFlags flags) override;
   void FlushNetworkAndNavigationInterfacesForTesting() override;
@@ -313,6 +313,7 @@
   void UpdateBrowserControlsState(BrowserControlsState constraints,
                                   BrowserControlsState current,
                                   bool animate) override;
+  void Reload() override;
 
   void SendAccessibilityEventsToManager(
       const AXEventNotificationDetails& details);
@@ -1178,6 +1179,8 @@
   // NavigationEntry this RenderFrameHostImpl committed.
   BackForwardCacheMetrics* GetBackForwardCacheMetrics();
 
+  const std::string& GetEncoding() const { return canonical_encoding_; }
+
   base::WeakPtr<RenderFrameHostImpl> GetWeakPtr();
 
  protected:
@@ -1812,11 +1815,10 @@
   std::unique_ptr<base::trace_event::TracedValue> CommitAsTracedValue(
       FrameHostMsg_DidCommitProvisionalLoad_Params* validated_params) const;
 
-  // Creates initiator-specific URLLoaderFactory objects for
-  // |initiator_origins|.
+  // Creates URLLoaderFactory objects for |isolated_world_origins|.
   blink::URLLoaderFactoryBundleInfo::OriginMap
-  CreateInitiatorSpecificURLLoaderFactories(
-      const base::flat_set<url::Origin>& initiator_origins);
+  CreateURLLoaderFactoriesForIsolatedWorlds(
+      const base::flat_set<url::Origin>& isolated_world_origins);
 
   // Based on the termination |status| and |exit_code|, may generate a crash
   // report to be routed to the Reporting API.
@@ -2366,14 +2368,15 @@
 
   // Whether UpdateSubresourceLoaderFactories should recreate the default
   // URLLoaderFactory when handling a NetworkService crash.  In case the frame
-  // is covered by AppCache, only initiator-specific factories need to be
+  // is covered by AppCache, only isolated-world-specific factories need to be
   // refreshed, but the main, AppCache-specific factory shouldn't be refreshed.
   bool recreate_default_url_loader_factory_after_network_service_crash_ = false;
 
-  // Set of request-initiator-origins that require a separate URLLoaderFactory
+  // Set of isolated world origins that require a separate URLLoaderFactory
   // (e.g. for handling requests initiated by extension content scripts that
   // require relaxed CORS/CORB rules).
-  base::flat_set<url::Origin> initiators_requiring_separate_url_loader_factory_;
+  base::flat_set<url::Origin>
+      isolated_worlds_requiring_separate_url_loader_factory_;
 
   // Holds the renderer generated ID and global request ID for the main frame
   // request.
@@ -2426,6 +2429,12 @@
   // browser side state as this value is used in security checks.
   bool is_mhtml_document_ = false;
 
+  // The last reported character encoding, not canonicalized.
+  std::string last_reported_encoding_;
+
+  // The canonicalized character encoding.
+  std::string canonical_encoding_;
+
   // Used to intercept DidCommit* calls in tests.
   CommitCallbackInterceptor* commit_callback_interceptor_;
 
diff --git a/content/browser/geolocation/geolocation_service_impl_unittest.cc b/content/browser/geolocation/geolocation_service_impl_unittest.cc
index e9e638c..45804e5 100644
--- a/content/browser/geolocation/geolocation_service_impl_unittest.cc
+++ b/content/browser/geolocation/geolocation_service_impl_unittest.cc
@@ -151,7 +151,7 @@
 }  // namespace
 
 TEST_F(GeolocationServiceTest, PermissionGrantedPolicyViolation) {
-  // The embedded frame is not whitelisted.
+  // The embedded frame is not allowed.
   CreateEmbeddedFrameAndGeolocationService(/*allow_via_feature_policy=*/false);
 
   permission_manager()->SetRequestCallback(
@@ -175,7 +175,7 @@
 }
 
 TEST_F(GeolocationServiceTest, PermissionGrantedNoPolicyViolation) {
-  // Whitelist the embedded frame.
+  // Allow the embedded frame.
   CreateEmbeddedFrameAndGeolocationService(/*allow_via_feature_policy=*/true);
 
   permission_manager()->SetRequestCallback(
diff --git a/content/browser/loader/loader_browsertest.cc b/content/browser/loader/loader_browsertest.cc
index 2b334fe2..89b2a7f8 100644
--- a/content/browser/loader/loader_browsertest.cc
+++ b/content/browser/loader/loader_browsertest.cc
@@ -295,7 +295,7 @@
   if (IsInProcessNetworkService())
     return;
 
-  embedded_test_server()->RegisterRequestHandler(base::Bind(
+  embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
       &CancelOnRequest, "/hung",
       shell()->web_contents()->GetMainFrame()->GetProcess()->GetID(),
       base::BindRepeating(&BrowserTestBase::SimulateNetworkServiceCrash,
@@ -376,7 +376,7 @@
 IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, CrossSiteNoUnloadOn204) {
   const char kNoContentPath[] = "/nocontent";
   embedded_test_server()->RegisterRequestHandler(
-      base::Bind(&NoContentResponseHandler, kNoContentPath));
+      base::BindRepeating(&NoContentResponseHandler, kNoContentPath));
 
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -566,7 +566,7 @@
 // navigations.
 IN_PROC_BROWSER_TEST_F(LoaderBrowserTest, CookiePolicy) {
   embedded_test_server()->RegisterRequestHandler(
-      base::Bind(&HandleRedirectRequest, "/redirect?"));
+      base::BindRepeating(&HandleRedirectRequest, "/redirect?"));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   std::string set_cookie_url(base::StringPrintf(
diff --git a/content/browser/loader/reload_cache_control_browsertest.cc b/content/browser/loader/reload_cache_control_browsertest.cc
index f5d87fa..702ef94 100644
--- a/content/browser/loader/reload_cache_control_browsertest.cc
+++ b/content/browser/loader/reload_cache_control_browsertest.cc
@@ -73,7 +73,7 @@
     // a registered HandleFileRequest for "content/test/data".
     // Because the handler is registered as the first handler, MonitorHandler
     // is needed to capture all requests.
-    embedded_test_server()->RegisterRequestMonitor(base::Bind(
+    embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
         &ReloadCacheControlBrowserTest::MonitorRequestHandler,
         base::Unretained(this)));
 
diff --git a/content/browser/media/media_devices_permission_checker_unittest.cc b/content/browser/media/media_devices_permission_checker_unittest.cc
index 40d9d80..e47200b 100644
--- a/content/browser/media/media_devices_permission_checker_unittest.cc
+++ b/content/browser/media/media_devices_permission_checker_unittest.cc
@@ -53,11 +53,11 @@
   void RefreshPageAndSetHeaderPolicy(blink::mojom::FeaturePolicyFeature feature,
                                      bool enabled) {
     NavigateAndCommit(origin_.GetURL());
-    std::vector<url::Origin> whitelist;
+    std::vector<url::Origin> allowlist;
     if (enabled)
-      whitelist.push_back(origin_);
+      allowlist.push_back(origin_);
     RenderFrameHostTester::For(main_rfh())
-        ->SimulateFeaturePolicyHeader(feature, whitelist);
+        ->SimulateFeaturePolicyHeader(feature, allowlist);
   }
 
   bool CheckPermission(blink::MediaDeviceType device_type) {
diff --git a/content/browser/native_file_system/file_system_chooser_browsertest.cc b/content/browser/native_file_system/file_system_chooser_browsertest.cc
index 777c18b8..e850282 100644
--- a/content/browser/native_file_system/file_system_chooser_browsertest.cc
+++ b/content/browser/native_file_system/file_system_chooser_browsertest.cc
@@ -15,6 +15,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/test/back_forward_cache_util.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
@@ -399,4 +400,26 @@
             dialog_params.file_types->extension_description_overrides[1]);
 }
 
+IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
+                       NativeFileSystemUsageDisablesBackForwardCache) {
+  BackForwardCacheDisabledTester tester;
+
+  const base::FilePath test_file = CreateTestFile("file contents");
+  SelectFileDialogParams dialog_params;
+  ui::SelectFileDialog::SetFactory(
+      new FakeSelectFileDialogFactory({test_file}, &dialog_params));
+  ASSERT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
+  EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let e = await self.chooseFileSystemEntries();"
+                   "  self.selected_entry = e;"
+                   "  return e.name; })()"));
+  EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
+      shell()->web_contents()->GetMainFrame()->GetProcess()->GetID(),
+      shell()->web_contents()->GetMainFrame()->GetRoutingID(),
+      "NativeFileSystem"));
+}
+
 }  // namespace content
diff --git a/content/browser/native_file_system/native_file_system_handle_base.cc b/content/browser/native_file_system/native_file_system_handle_base.cc
index b92e673e..6300265 100644
--- a/content/browser/native_file_system/native_file_system_handle_base.cc
+++ b/content/browser/native_file_system/native_file_system_handle_base.cc
@@ -7,6 +7,7 @@
 #include "base/task/post_task.h"
 #include "content/browser/native_file_system/native_file_system_error.h"
 #include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/web_contents_observer.h"
 
@@ -24,6 +25,10 @@
         is_directory_(is_directory),
         directory_path_(directory_path) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    // Disable back-forward cache as native file system's usage of
+    // RenderFrameHost::IsCurrent at the moment is not compatible with bfcache.
+    BackForwardCache::DisableForRenderFrameHost(
+        GlobalFrameRoutingId(process_id, frame_id), "NativeFileSystem");
     if (web_contents()) {
       web_contents()->IncrementNativeFileSystemHandleCount();
       if (is_directory_)
diff --git a/content/browser/permissions/permission_controller_impl.cc b/content/browser/permissions/permission_controller_impl.cc
index a018bcbf..09fe4c5 100644
--- a/content/browser/permissions/permission_controller_impl.cc
+++ b/content/browser/permissions/permission_controller_impl.cc
@@ -125,7 +125,7 @@
   GURL embedding_origin;
   int render_frame_id = -1;
   int render_process_id = -1;
-  base::Callback<void(blink::mojom::PermissionStatus)> callback;
+  base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback;
   int delegate_subscription_id;
 };
 
@@ -166,7 +166,7 @@
 
 void PermissionControllerImpl::NotifyChangedSubscriptions(
     const SubscriptionsStatusMap& old_statuses) {
-  std::vector<base::Closure> callbacks;
+  std::vector<base::OnceClosure> callbacks;
   for (const auto& it : old_statuses) {
     auto key = it.first;
     Subscription* subscription = subscriptions_.Lookup(key);
@@ -176,10 +176,10 @@
     blink::mojom::PermissionStatus new_status =
         GetSubscriptionCurrentValue(*subscription);
     if (new_status != old_status)
-      callbacks.push_back(base::Bind(subscription->callback, new_status));
+      callbacks.push_back(base::BindOnce(subscription->callback, new_status));
   }
-  for (const auto& callback : callbacks)
-    callback.Run();
+  for (auto& callback : callbacks)
+    std::move(callback).Run();
 }
 
 PermissionControllerImpl::OverrideStatus
@@ -256,25 +256,26 @@
     RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
     bool user_gesture,
-    const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
+    base::OnceCallback<void(blink::mojom::PermissionStatus)> callback) {
   NotifySchedulerAboutPermissionRequest(render_frame_host, permission);
 
   base::Optional<blink::mojom::PermissionStatus> status_override =
       devtools_permission_overrides_.Get(url::Origin::Create(requesting_origin),
                                          permission);
   if (status_override.has_value()) {
-    callback.Run(*status_override);
+    std::move(callback).Run(*status_override);
     return kNoPendingOperation;
   }
 
   PermissionControllerDelegate* delegate =
       browser_context_->GetPermissionControllerDelegate();
   if (!delegate) {
-    callback.Run(blink::mojom::PermissionStatus::DENIED);
+    std::move(callback).Run(blink::mojom::PermissionStatus::DENIED);
     return kNoPendingOperation;
   }
   return delegate->RequestPermission(permission, render_frame_host,
-                                     requesting_origin, user_gesture, callback);
+                                     requesting_origin, user_gesture,
+                                     std::move(callback));
 }
 
 int PermissionControllerImpl::RequestPermissions(
@@ -282,8 +283,8 @@
     RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
     bool user_gesture,
-    const base::Callback<
-        void(const std::vector<blink::mojom::PermissionStatus>&)>& callback) {
+    base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)>
+        callback) {
   for (PermissionType permission : permissions)
     NotifySchedulerAboutPermissionRequest(render_frame_host, permission);
 
@@ -382,7 +383,8 @@
     PermissionType permission,
     RenderFrameHost* render_frame_host,
     const GURL& requesting_origin,
-    const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
+    const base::RepeatingCallback<void(blink::mojom::PermissionStatus)>&
+        callback) {
   auto subscription = std::make_unique<Subscription>();
   subscription->permission = permission;
   subscription->callback = callback;
@@ -408,7 +410,7 @@
     subscription->delegate_subscription_id =
         delegate->SubscribePermissionStatusChange(
             permission, render_frame_host, requesting_origin,
-            base::Bind(
+            base::BindRepeating(
                 &PermissionControllerImpl::OnDelegatePermissionStatusChange,
                 base::Unretained(this), subscription.get()));
   } else {
diff --git a/content/browser/permissions/permission_controller_impl.h b/content/browser/permissions/permission_controller_impl.h
index 86f121c..0c5e652 100644
--- a/content/browser/permissions/permission_controller_impl.h
+++ b/content/browser/permissions/permission_controller_impl.h
@@ -57,15 +57,15 @@
       RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
       bool user_gesture,
-      const base::Callback<void(blink::mojom::PermissionStatus)>& callback);
+      base::OnceCallback<void(blink::mojom::PermissionStatus)> callback);
 
   int RequestPermissions(
       const std::vector<PermissionType>& permission,
       RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
       bool user_gesture,
-      const base::Callback<
-          void(const std::vector<blink::mojom::PermissionStatus>&)>& callback);
+      base::OnceCallback<
+          void(const std::vector<blink::mojom::PermissionStatus>&)> callback);
 
   void ResetPermission(PermissionType permission,
                        const GURL& requesting_origin,
@@ -75,7 +75,8 @@
       PermissionType permission,
       RenderFrameHost* render_frame_host,
       const GURL& requesting_origin,
-      const base::Callback<void(blink::mojom::PermissionStatus)>& callback);
+      const base::RepeatingCallback<void(blink::mojom::PermissionStatus)>&
+          callback);
 
   void UnsubscribePermissionStatusChange(int subscription_id);
 
diff --git a/content/browser/permissions/permission_controller_impl_unittest.cc b/content/browser/permissions/permission_controller_impl_unittest.cc
index c408b18c..2685e749 100644
--- a/content/browser/permissions/permission_controller_impl_unittest.cc
+++ b/content/browser/permissions/permission_controller_impl_unittest.cc
@@ -23,8 +23,8 @@
 namespace {
 using ::testing::Unused;
 using OverrideStatus = PermissionControllerImpl::OverrideStatus;
-using RequestsCallback =
-    base::Callback<void(const std::vector<blink::mojom::PermissionStatus>&)>;
+using RequestsCallback = base::OnceCallback<void(
+    const std::vector<blink::mojom::PermissionStatus>&)>;
 
 constexpr char kTestUrl[] = "https://google.com";
 
diff --git a/content/browser/permissions/permission_service_impl.cc b/content/browser/permissions/permission_service_impl.cc
index 4fffcdd..c6345e0 100644
--- a/content/browser/permissions/permission_service_impl.cc
+++ b/content/browser/permissions/permission_service_impl.cc
@@ -211,13 +211,13 @@
       std::make_unique<PendingRequest>(types, std::move(callback));
 
   int pending_request_id = pending_requests_.Add(std::move(pending_request));
-  int id =
-      PermissionControllerImpl::FromBrowserContext(browser_context)
-          ->RequestPermissions(
-              types, context_->render_frame_host(), origin_.GetURL(),
-              user_gesture,
-              base::Bind(&PermissionServiceImpl::OnRequestPermissionsResponse,
-                         weak_factory_.GetWeakPtr(), pending_request_id));
+  int id = PermissionControllerImpl::FromBrowserContext(browser_context)
+               ->RequestPermissions(
+                   types, context_->render_frame_host(), origin_.GetURL(),
+                   user_gesture,
+                   base::BindOnce(
+                       &PermissionServiceImpl::OnRequestPermissionsResponse,
+                       weak_factory_.GetWeakPtr(), pending_request_id));
 
   // Check if the request still exists. It may have been removed by the
   // the response callback.
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 9db86e1f..e48d150 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -538,6 +538,10 @@
   host_->SetNeedsAnimate();
 }
 
+void CompositorImpl::SetNeedsRedraw() {
+  host_->SetNeedsRedrawRect(host_->device_viewport_rect());
+}
+
 void CompositorImpl::DidUpdateLayers() {
   // Dump property trees and layers if run with:
   //   --vmodule=compositor_impl_android=3
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index c799299..58573a01 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -98,6 +98,7 @@
   void SetWindowBounds(const gfx::Size& size) override;
   void SetRequiresAlphaChannel(bool flag) override;
   void SetNeedsComposite() override;
+  void SetNeedsRedraw() override;
   ui::UIResourceProvider& GetUIResourceProvider() override;
   ui::ResourceManager& GetResourceManager() override;
   void CacheBackBufferForCurrentSurface() override;
diff --git a/content/browser/renderer_host/input/scroll_latency_browsertest.cc b/content/browser/renderer_host/input/scroll_latency_browsertest.cc
index 14c2a59..cbe4dc8 100644
--- a/content/browser/renderer_host/input/scroll_latency_browsertest.cc
+++ b/content/browser/renderer_host/input/scroll_latency_browsertest.cc
@@ -274,12 +274,9 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ScrollLatencyBrowserTest::SetUpCommandLine(command_line);
     command_line->AppendSwitch(::switches::kDisableSmoothScrolling);
-    // Enable |kScrollbarInjectScrollGestures|, as these tests depend on it
-    // being on. Disable kOverlayScrollbar since overlay scrollbars are not
+    // Disable kOverlayScrollbar since overlay scrollbars are not
     // hit-testable (thus input is not routed to scrollbars).
-    scoped_feature_list_.InitWithFeatures(
-        {blink::features::kScrollbarInjectScrollGestures},
-        {features::kOverlayScrollbar});
+    scoped_feature_list_.InitAndDisableFeature({features::kOverlayScrollbar});
   }
 
   ~ScrollLatencyScrollbarBrowserTest() override {}
diff --git a/content/browser/renderer_host/input/timeout_monitor.h b/content/browser/renderer_host/input/timeout_monitor.h
index ddec7c1..ff7ae6d 100644
--- a/content/browser/renderer_host/input/timeout_monitor.h
+++ b/content/browser/renderer_host/input/timeout_monitor.h
@@ -16,7 +16,7 @@
 // Utility class for handling a timeout callback with periodic starts and stops.
 class CONTENT_EXPORT TimeoutMonitor {
  public:
-  typedef base::Closure TimeoutHandler;
+  typedef base::RepeatingClosure TimeoutHandler;
 
   explicit TimeoutMonitor(const TimeoutHandler& timeout_handler);
   ~TimeoutMonitor();
diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
index 9889674..2e92ce4 100644
--- a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
@@ -374,9 +374,9 @@
   void RefreshPageAndSetHeaderPolicy(
       blink::mojom::FeaturePolicyFeature feature) {
     NavigateAndCommit(main_rfh()->GetLastCommittedURL());
-    std::vector<url::Origin> empty_whitelist;
+    std::vector<url::Origin> empty_allowlist;
     RenderFrameHostTester::For(main_rfh())
-        ->SimulateFeaturePolicyHeader(feature, empty_whitelist);
+        ->SimulateFeaturePolicyHeader(feature, empty_allowlist);
   }
 
   void GetResultForRequest(std::unique_ptr<MediaStreamRequest> request,
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index f4ba069..3596ee36 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -865,6 +865,16 @@
       process_id(), MakeRequest(&params->provider_info->interface_provider),
       params->provider_info->browser_interface_broker
           .InitWithNewPipeAndPassReceiver());
+
+  // TODO(bashi): Create correct outside fetch client settings object. We need
+  // to plumb parent's fetch client settings object from renderer.
+  // See crbug.com/937177.
+  params->outside_fetch_client_settings_object =
+      blink::mojom::FetchClientSettingsObject::New(
+          network::mojom::ReferrerPolicy::kDefault,
+          /*outgoing_referrer=*/params->script_url,
+          blink::mojom::InsecureRequestsPolicy::kDoNotUpgrade);
+
   client_->StartWorker(std::move(params));
 
   starting_phase_ = is_script_streaming ? SCRIPT_STREAMING : SENT_START_WORKER;
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index 8e83f9ed..de9c8f5 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -17,8 +17,10 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/services/leveldb/public/cpp/util.h"
+#include "components/services/storage/dom_storage/dom_storage_database.h"
 #include "content/browser/code_cache/generated_code_cache.h"
 #include "content/browser/code_cache/generated_code_cache_context.h"
+#include "content/browser/dom_storage/local_storage_context_mojo.h"
 #include "content/browser/dom_storage/local_storage_database.pb.h"
 #include "content/browser/gpu/shader_cache_factory.h"
 #include "content/browser/storage_partition_impl.h"
@@ -31,7 +33,6 @@
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_utils.h"
-#include "content/test/fake_leveldb_database.h"
 #include "net/base/test_completion_callback.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_store.h"
@@ -191,11 +192,21 @@
 
 class RemoveLocalStorageTester {
  public:
-  explicit RemoveLocalStorageTester(TestBrowserContext* profile)
-      : dom_storage_context_(nullptr) {
+  RemoveLocalStorageTester(content::BrowserTaskEnvironment* task_environment,
+                           TestBrowserContext* profile)
+      : task_environment_(task_environment), dom_storage_context_(nullptr) {
     dom_storage_context_ =
-        content::BrowserContext::GetDefaultStoragePartition(profile)->
-            GetDOMStorageContext();
+        content::BrowserContext::GetDefaultStoragePartition(profile)
+            ->GetDOMStorageContext();
+  }
+
+  ~RemoveLocalStorageTester() {
+    // Tests which bring up a real Local Storage context need to shut it down
+    // and wait for the database to be closed before terminating; otherwise the
+    // TestBrowserContext may fail to delete its temp dir, and it will not be
+    // happy about that.
+    static_cast<DOMStorageContextWrapper*>(dom_storage_context_)->Shutdown();
+    task_environment_->RunUntilIdle();
   }
 
   // Returns true, if the given origin URL exists.
@@ -214,35 +225,45 @@
     // stores data in the database.
 
     static_cast<DOMStorageContextWrapper*>(dom_storage_context_)
-        ->SetLocalStorageDatabaseFactoryForTesting(base::BindLambdaForTesting(
-            [&]() -> std::unique_ptr<leveldb::mojom::LevelDBDatabase> {
-              return std::make_unique<FakeLevelDBDatabase>(&mock_data_);
+        ->SetLocalStorageDatabaseOpenCallbackForTesting(
+            base::BindLambdaForTesting([&](LocalStorageContextMojo* context) {
+              context->GetDatabaseForTesting().PostTaskWithThisObject(
+                  FROM_HERE, base::BindOnce(&PopulateDatabase));
             }));
+  }
 
+  static void PopulateDatabase(const storage::DomStorageDatabase& db) {
     LocalStorageOriginMetaData data;
+    std::map<std::vector<uint8_t>, std::vector<uint8_t>> entries;
 
     base::Time now = base::Time::Now();
     data.set_last_modified(now.ToInternalValue());
     data.set_size_bytes(16);
-    mock_data_[CreateMetaDataKey(kOrigin1)] =
-        leveldb::StdStringToUint8Vector(data.SerializeAsString());
-    mock_data_[CreateDataKey(kOrigin1)] = {};
+    ASSERT_TRUE(
+        db.Put(CreateMetaDataKey(kOrigin1),
+               leveldb::StdStringToUint8Vector(data.SerializeAsString()))
+            .ok());
+    ASSERT_TRUE(db.Put(CreateDataKey(kOrigin1), {}).ok());
 
     base::Time one_day_ago = now - base::TimeDelta::FromDays(1);
     data.set_last_modified(one_day_ago.ToInternalValue());
-    mock_data_[CreateMetaDataKey(kOrigin2)] =
-        leveldb::StdStringToUint8Vector(data.SerializeAsString());
-    mock_data_[CreateDataKey(kOrigin2)] = {};
+    ASSERT_TRUE(
+        db.Put(CreateMetaDataKey(kOrigin2),
+               leveldb::StdStringToUint8Vector(data.SerializeAsString()))
+            .ok());
+    ASSERT_TRUE(db.Put(CreateDataKey(kOrigin2), {}).ok());
 
     base::Time sixty_days_ago = now - base::TimeDelta::FromDays(60);
     data.set_last_modified(sixty_days_ago.ToInternalValue());
-    mock_data_[CreateMetaDataKey(kOrigin3)] =
-        leveldb::StdStringToUint8Vector(data.SerializeAsString());
-    mock_data_[CreateDataKey(kOrigin3)] = {};
+    ASSERT_TRUE(
+        db.Put(CreateMetaDataKey(kOrigin3),
+               leveldb::StdStringToUint8Vector(data.SerializeAsString()))
+            .ok());
+    ASSERT_TRUE(db.Put(CreateDataKey(kOrigin3), {}).ok());
   }
 
  private:
-  std::vector<uint8_t> CreateDataKey(const url::Origin& origin) {
+  static std::vector<uint8_t> CreateDataKey(const url::Origin& origin) {
     auto serialized_origin =
         leveldb::StdStringToUint8Vector(origin.Serialize());
     std::vector<uint8_t> key = {'_'};
@@ -252,7 +273,7 @@
     return key;
   }
 
-  std::vector<uint8_t> CreateMetaDataKey(const url::Origin& origin) {
+  static std::vector<uint8_t> CreateMetaDataKey(const url::Origin& origin) {
     const uint8_t kMetaPrefix[] = {'M', 'E', 'T', 'A', ':'};
     auto serialized_origin =
         leveldb::StdStringToUint8Vector(origin.Serialize());
@@ -276,10 +297,9 @@
   }
 
   // We don't own these pointers.
+  content::BrowserTaskEnvironment* const task_environment_;
   content::DOMStorageContext* dom_storage_context_;
 
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_;
-
   std::vector<content::StorageUsageInfo> infos_;
 
   AwaitCompletionHelper await_completion_;
@@ -586,21 +606,19 @@
                        base::Time::Max(), loop_to_quit->QuitClosure());
 }
 
-void ClearQuotaDataForOrigin(
-    content::StoragePartition* partition,
-    const GURL& remove_origin,
-    const base::Time delete_begin,
-    base::RunLoop* loop_to_quit) {
+void ClearQuotaDataForOrigin(content::StoragePartition* partition,
+                             const GURL& remove_origin,
+                             const base::Time delete_begin,
+                             base::RunLoop* loop_to_quit) {
   partition->ClearData(kAllQuotaRemoveMask,
                        StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
                        remove_origin, delete_begin, base::Time::Max(),
                        loop_to_quit->QuitClosure());
 }
 
-void ClearQuotaDataForNonPersistent(
-    content::StoragePartition* partition,
-    const base::Time delete_begin,
-    base::RunLoop* loop_to_quit) {
+void ClearQuotaDataForNonPersistent(content::StoragePartition* partition,
+                                    const base::Time delete_begin,
+                                    base::RunLoop* loop_to_quit) {
   partition->ClearData(kAllQuotaRemoveMask,
                        ~StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT,
                        GURL(), delete_begin, base::Time::Max(),
@@ -644,8 +662,7 @@
                        run_loop->QuitClosure());
 }
 
-void ClearData(content::StoragePartition* partition,
-               base::RunLoop* run_loop) {
+void ClearData(content::StoragePartition* partition, base::RunLoop* run_loop) {
   base::Time time;
   partition->ClearData(StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE,
                        StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, GURL(),
@@ -703,8 +720,10 @@
     return quota_manager_.get();
   }
 
-  TestBrowserContext* browser_context() {
-    return browser_context_.get();
+  TestBrowserContext* browser_context() { return browser_context_.get(); }
+
+  content::BrowserTaskEnvironment* task_environment() {
+    return &task_environment_;
   }
 
  private:
@@ -749,9 +768,7 @@
 
   size_t Size() { return cache_->Size(); }
 
-  TestBrowserContext* browser_context() {
-    return browser_context_.get();
-  }
+  TestBrowserContext* browser_context() { return browser_context_.get(); }
 
  private:
   content::BrowserTaskEnvironment task_environment_;
@@ -835,8 +852,7 @@
 
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
-  partition->OverrideQuotaManagerForTesting(
-      GetMockManager());
+  partition->OverrideQuotaManagerForTesting(GetMockManager());
 
   base::RunLoop run_loop;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -862,8 +878,7 @@
 
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
-  partition->OverrideQuotaManagerForTesting(
-      GetMockManager());
+  partition->OverrideQuotaManagerForTesting(GetMockManager());
 
   base::RunLoop run_loop;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -889,8 +904,7 @@
 
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
-  partition->OverrideQuotaManagerForTesting(
-      GetMockManager());
+  partition->OverrideQuotaManagerForTesting(GetMockManager());
 
   base::RunLoop run_loop;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -914,8 +928,7 @@
 TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForeverNeither) {
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
-  partition->OverrideQuotaManagerForTesting(
-      GetMockManager());
+  partition->OverrideQuotaManagerForTesting(GetMockManager());
 
   base::RunLoop run_loop;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -941,8 +954,7 @@
 
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
-  partition->OverrideQuotaManagerForTesting(
-      GetMockManager());
+  partition->OverrideQuotaManagerForTesting(GetMockManager());
 
   base::RunLoop run_loop;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -969,8 +981,7 @@
 
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
-  partition->OverrideQuotaManagerForTesting(
-      GetMockManager());
+  partition->OverrideQuotaManagerForTesting(GetMockManager());
 
   base::RunLoop run_loop;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -1000,8 +1011,7 @@
   base::RunLoop run_loop;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
-  partition->OverrideQuotaManagerForTesting(
-      GetMockManager());
+  partition->OverrideQuotaManagerForTesting(GetMockManager());
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&ClearQuotaDataForNonPersistent, partition,
@@ -1033,8 +1043,7 @@
 
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
-  partition->OverrideQuotaManagerForTesting(
-      GetMockManager());
+  partition->OverrideQuotaManagerForTesting(GetMockManager());
   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
 
   base::RunLoop run_loop;
@@ -1071,8 +1080,7 @@
   base::RunLoop run_loop;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
-  partition->OverrideQuotaManagerForTesting(
-      GetMockManager());
+  partition->OverrideQuotaManagerForTesting(GetMockManager());
   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
@@ -1102,8 +1110,7 @@
   base::RunLoop run_loop;
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(browser_context()));
-  partition->OverrideQuotaManagerForTesting(
-      GetMockManager());
+  partition->OverrideQuotaManagerForTesting(GetMockManager());
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&ClearQuotaDataWithOriginMatcher, partition,
@@ -1176,7 +1183,7 @@
       new MockSpecialStoragePolicy;
   mock_policy->AddProtected(kOrigin1.GetURL());
 
-  RemoveLocalStorageTester tester(browser_context());
+  RemoveLocalStorageTester tester(task_environment(), browser_context());
 
   tester.AddDOMStorageTestData();
   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin1));
@@ -1211,7 +1218,7 @@
       new MockSpecialStoragePolicy;
   mock_policy->AddProtected(kOrigin1.GetURL());
 
-  RemoveLocalStorageTester tester(browser_context());
+  RemoveLocalStorageTester tester(task_environment(), browser_context());
 
   tester.AddDOMStorageTestData();
   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin1));
@@ -1245,7 +1252,7 @@
 }
 
 TEST_F(StoragePartitionImplTest, RemoveLocalStorageForLastWeek) {
-  RemoveLocalStorageTester tester(browser_context());
+  RemoveLocalStorageTester tester(task_environment(), browser_context());
 
   tester.AddDOMStorageTestData();
   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin1));
diff --git a/content/browser/tracing/memory_instrumentation_browsertest.cc b/content/browser/tracing/memory_instrumentation_browsertest.cc
index 0afeead..0283f6f 100644
--- a/content/browser/tracing/memory_instrumentation_browsertest.cc
+++ b/content/browser/tracing/memory_instrumentation_browsertest.cc
@@ -79,9 +79,8 @@
 
 // *SAN fake some sys calls we need meaning we never get dumps for the
 // processes.
-// Flakes on Android. crbug.com/970058
 #if defined(MEMORY_SANITIZER) || defined(ADDRESS_SANITIZER) || \
-    defined(THREAD_SANITIZER) || defined(OS_ANDROID)
+    defined(THREAD_SANITIZER)
 #define MAYBE_PrivateFootprintComputation DISABLED_PrivateFootprintComputation
 #else
 #define MAYBE_PrivateFootprintComputation PrivateFootprintComputation
diff --git a/content/browser/tracing/memory_instrumentation_util.cc b/content/browser/tracing/memory_instrumentation_util.cc
new file mode 100644
index 0000000..10b01d41
--- /dev/null
+++ b/content/browser/tracing/memory_instrumentation_util.cc
@@ -0,0 +1,26 @@
+// 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 "content/browser/tracing/memory_instrumentation_util.h"
+
+#include "content/public/browser/resource_coordinator_service.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
+
+namespace content {
+
+void InitializeBrowserMemoryInstrumentationClient() {
+  mojo::PendingRemote<memory_instrumentation::mojom::Coordinator> coordinator;
+  mojo::PendingRemote<memory_instrumentation::mojom::ClientProcess> process;
+  auto process_receiver = process.InitWithNewPipeAndPassReceiver();
+  GetMemoryInstrumentationCoordinatorController()->RegisterClientProcess(
+      coordinator.InitWithNewPipeAndPassReceiver(), std::move(process),
+      memory_instrumentation::mojom::ProcessType::BROWSER,
+      base::GetCurrentProcId(), /*service_name=*/base::nullopt);
+  memory_instrumentation::ClientProcessImpl::CreateInstance(
+      std::move(process_receiver), std::move(coordinator),
+      /*is_browser_process=*/true);
+}
+
+}  // namespace content
diff --git a/content/browser/tracing/memory_instrumentation_util.h b/content/browser/tracing/memory_instrumentation_util.h
new file mode 100644
index 0000000..95fc27ec
--- /dev/null
+++ b/content/browser/tracing/memory_instrumentation_util.h
@@ -0,0 +1,18 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_TRACING_MEMORY_INSTRUMENTATION_UTIL_H_
+#define CONTENT_BROWSER_TRACING_MEMORY_INSTRUMENTATION_UTIL_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Registers the browser process as a memory-instrumentation client, so that
+// data for the browser process will be available in memory dumps.
+void CONTENT_EXPORT InitializeBrowserMemoryInstrumentationClient();
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_TRACING_MEMORY_INSTRUMENTATION_UTIL_H_
diff --git a/content/browser/tracing/memory_tracing_browsertest.cc b/content/browser/tracing/memory_tracing_browsertest.cc
index 2bf39e5d..2f47e54 100644
--- a/content/browser/tracing/memory_tracing_browsertest.cc
+++ b/content/browser/tracing/memory_tracing_browsertest.cc
@@ -180,10 +180,9 @@
 // intended to give coverage to Android WebView.
 #if defined(OS_ANDROID)
 
-// Flaky on Android. crbug.com/970058
-class DISABLED_SingleProcessMemoryTracingTest : public MemoryTracingTest {
+class SingleProcessMemoryTracingTest : public MemoryTracingTest {
  public:
-  DISABLED_SingleProcessMemoryTracingTest() {}
+  SingleProcessMemoryTracingTest() {}
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(switches::kSingleProcess);
@@ -191,15 +190,15 @@
 };
 
 // https://crbug.com/788788
-#if defined(ADDRESS_SANITIZER)
+#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
 #define MAYBE_BrowserInitiatedSingleDump DISABLED_BrowserInitiatedSingleDump
 #else
 #define MAYBE_BrowserInitiatedSingleDump BrowserInitiatedSingleDump
-#endif  // defined(ADDRESS_SANITIZER)
+#endif  // defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
 
 // Checks that a memory dump initiated from a the main browser thread ends up in
 // a single dump even in single process mode.
-IN_PROC_BROWSER_TEST_F(DISABLED_SingleProcessMemoryTracingTest,
+IN_PROC_BROWSER_TEST_F(SingleProcessMemoryTracingTest,
                        MAYBE_BrowserInitiatedSingleDump) {
   Navigate(shell());
 
@@ -214,16 +213,16 @@
 }
 
 // https://crbug.com/788788
-#if defined(ADDRESS_SANITIZER)
+#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
 #define MAYBE_RendererInitiatedSingleDump DISABLED_RendererInitiatedSingleDump
 #else
 #define MAYBE_RendererInitiatedSingleDump RendererInitiatedSingleDump
-#endif  // defined(ADDRESS_SANITIZER)
+#endif  // defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
 
 // Checks that a memory dump initiated from a renderer thread ends up in a
 // single dump even in single process mode.
-IN_PROC_BROWSER_TEST_F(DISABLED_SingleProcessMemoryTracingTest,
-                       DISABLED_RendererInitiatedSingleDump) {
+IN_PROC_BROWSER_TEST_F(SingleProcessMemoryTracingTest,
+                       MAYBE_RendererInitiatedSingleDump) {
   Navigate(shell());
 
   EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_,_)).WillOnce(Return(true));
@@ -237,12 +236,12 @@
 }
 
 // https://crbug.com/788788
-#if defined(ADDRESS_SANITIZER)
+#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
 #define MAYBE_ManyInterleavedDumps DISABLED_ManyInterleavedDumps
 #else
 #define MAYBE_ManyInterleavedDumps ManyInterleavedDumps
-#endif  // defined(ADDRESS_SANITIZER)
-IN_PROC_BROWSER_TEST_F(DISABLED_SingleProcessMemoryTracingTest,
+#endif  // defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
+IN_PROC_BROWSER_TEST_F(SingleProcessMemoryTracingTest,
                        MAYBE_ManyInterleavedDumps) {
   Navigate(shell());
 
@@ -272,8 +271,7 @@
 // that periodic dump requests fail in case there is already a request in the
 // queue with the same level of detail.
 // Flaky failures on all platforms. https://crbug.com/752613
-IN_PROC_BROWSER_TEST_F(DISABLED_SingleProcessMemoryTracingTest,
-                       DISABLED_QueuedDumps) {
+IN_PROC_BROWSER_TEST_F(SingleProcessMemoryTracingTest, DISABLED_QueuedDumps) {
   Navigate(shell());
 
   EnableMemoryTracing();
@@ -339,7 +337,7 @@
 #endif  // defined(OS_ANDROID)
 
 // Flaky on Mac. crbug.com/809809
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
+#if defined(OS_MACOSX)
 #define MAYBE_BrowserInitiatedDump DISABLED_BrowserInitiatedDump
 #else
 #define MAYBE_BrowserInitiatedDump BrowserInitiatedDump
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index f5046dd..2db4e71 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -39,6 +39,8 @@
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/base/network_change_notifier.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "services/tracing/public/cpp/perfetto/java_heap_profiler/java_heap_profiler.h"
+#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
 #include "services/tracing/public/cpp/trace_event_agent.h"
 #include "services/tracing/public/cpp/traced_process_impl.h"
 #include "services/tracing/public/cpp/tracing_features.h"
@@ -210,6 +212,8 @@
         base::BindRepeating(&TracingDelegate::GenerateMetadataDict,
                             base::Unretained(delegate_.get())));
   }
+  tracing::PerfettoTracedProcess::Get()->AddDataSource(
+      tracing::JavaHeapProfiler::GetInstance());
 }
 
 void TracingControllerImpl::ConnectToServiceIfNeeded() {
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 91c9a1c..0660fdd8 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -15,7 +15,6 @@
 #include "base/debug/dump_without_crashing.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
-#include "base/i18n/character_encoding.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -1448,7 +1447,7 @@
 }
 
 const std::string& WebContentsImpl::GetEncoding() {
-  return canonical_encoding_;
+  return GetMainFrame()->GetEncoding();
 }
 
 bool WebContentsImpl::WasDiscarded() {
@@ -3675,10 +3674,7 @@
   if (!focused_frame)
     return;
 
-  // TODO(https://crbug.com/995428). This function is deprecated. Navigations
-  // are handled from the browser process. There is no need to send an IPC to
-  // the renderer process for this.
-  focused_frame->Send(new FrameMsg_Reload(focused_frame->GetRoutingID()));
+  focused_frame->Reload();
 }
 
 std::vector<mojo::Remote<blink::mojom::PauseSubresourceLoadingHandle>>
@@ -6184,11 +6180,6 @@
   UpdateTitleForEntry(entry, title);
 }
 
-void WebContentsImpl::UpdateEncoding(RenderFrameHost* render_frame_host,
-                                     const std::string& encoding) {
-  SetEncoding(encoding);
-}
-
 void WebContentsImpl::DocumentAvailableInMainFrame(
     RenderViewHost* render_view_host) {
   for (auto& observer : observers_)
@@ -6772,14 +6763,6 @@
   is_showing_before_unload_dialog_ = false;
 }
 
-void WebContentsImpl::SetEncoding(const std::string& encoding) {
-  if (encoding == last_reported_encoding_)
-    return;
-  last_reported_encoding_ = encoding;
-
-  canonical_encoding_ = base::GetCanonicalEncodingNameByAliasName(encoding);
-}
-
 bool WebContentsImpl::IsHidden() {
   return !IsBeingCaptured() && visibility_ != Visibility::VISIBLE;
 }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index b63b0d0..47de584 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -552,8 +552,6 @@
   void UpdateTitle(RenderFrameHost* render_frame_host,
                    const base::string16& title,
                    base::i18n::TextDirection title_direction) override;
-  void UpdateEncoding(RenderFrameHost* render_frame_host,
-                      const std::string& encoding) override;
   WebContents* GetAsWebContents() override;
   bool IsNeverVisible() override;
   ui::AXMode GetAccessibilityMode() override;
@@ -1466,8 +1464,6 @@
                           bool is_main_frame);
   void NotifyDisconnected();
 
-  void SetEncoding(const std::string& encoding);
-
   // TODO(creis): This should take in a FrameTreeNode to know which node's
   // render manager to return.  For now, we just return the root's.
   RenderFrameHostManager* GetRenderManager() const;
@@ -1637,12 +1633,6 @@
   // used to check whether we can do something for some special contents.
   std::string contents_mime_type_;
 
-  // The last reported character encoding, not canonicalized.
-  std::string last_reported_encoding_;
-
-  // The canonicalized character encoding.
-  std::string canonical_encoding_;
-
   // Whether the initial empty page has been accessed by another page, making it
   // unsafe to show the pending URL. Usually false unless another window tries
   // to modify the blank page.  Always false after the first commit.
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc
index 39edc87..1e26a4e 100644
--- a/content/browser/webui/web_ui_url_loader_factory.cc
+++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -81,17 +81,26 @@
 
   uint32_t output_size = bytes->size();
 
-  mojo::DataPipe data_pipe(output_size);
+  MojoCreateDataPipeOptions options;
+  options.struct_size = sizeof(MojoCreateDataPipeOptions);
+  options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+  options.element_num_bytes = 1;
+  options.capacity_num_bytes = output_size;
+  mojo::ScopedDataPipeProducerHandle pipe_producer_handle;
+  mojo::ScopedDataPipeConsumerHandle pipe_consumer_handle;
+  MojoResult create_result = mojo::CreateDataPipe(
+      &options, &pipe_producer_handle, &pipe_consumer_handle);
+  CHECK_EQ(create_result, MOJO_RESULT_OK);
 
   void* buffer = nullptr;
   uint32_t num_bytes = output_size;
-  MojoResult result = data_pipe.producer_handle->BeginWriteData(
+  MojoResult result = pipe_producer_handle->BeginWriteData(
       &buffer, &num_bytes, MOJO_WRITE_DATA_FLAG_NONE);
   CHECK_EQ(result, MOJO_RESULT_OK);
   CHECK_GE(num_bytes, output_size);
 
   memcpy(buffer, bytes->front(), output_size);
-  result = data_pipe.producer_handle->EndWriteData(output_size);
+  result = pipe_producer_handle->EndWriteData(output_size);
   CHECK_EQ(result, MOJO_RESULT_OK);
 
   // For media content, |content_length| must be known upfront for data that is
@@ -104,7 +113,7 @@
   client.Bind(std::move(client_info));
   client->OnReceiveResponse(headers->head);
 
-  client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
+  client->OnStartLoadingResponseBody(std::move(pipe_consumer_handle));
   network::URLLoaderCompletionStatus status(net::OK);
   status.encoded_data_length = output_size;
   status.encoded_body_length = output_size;
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index b8018f5..35c3889e 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -337,6 +337,10 @@
   WebRuntimeFeatures::EnableImplicitRootScroller(
       base::FeatureList::IsEnabled(blink::features::kImplicitRootScroller));
 
+  if (base::FeatureList::IsEnabled(
+          blink::features::kCSSOMViewScrollCoordinates))
+    WebRuntimeFeatures::EnableCSSOMViewScrollCoordinates(true);
+
   WebRuntimeFeatures::EnableTextFragmentAnchor(
       base::FeatureList::IsEnabled(blink::features::kTextFragmentAnchor));
 
diff --git a/content/public/android/java/src/org/chromium/content/app/KillChildUncaughtExceptionHandler.java b/content/public/android/java/src/org/chromium/content/app/KillChildUncaughtExceptionHandler.java
index 22f7897f..eb2e80c 100644
--- a/content/public/android/java/src/org/chromium/content/app/KillChildUncaughtExceptionHandler.java
+++ b/content/public/android/java/src/org/chromium/content/app/KillChildUncaughtExceptionHandler.java
@@ -35,12 +35,13 @@
     }
 
     @Override
+    @SuppressWarnings("checkstyle:SystemExitCheck") // Allowed since the goal is to mimic Android.
     public void uncaughtException(Thread t, Throwable e) {
         // Never re-enter.
         if (mCrashing) return;
         mCrashing = true;
 
-        // Copyed from Android KillApplicationHandler in RuntimeInit.java. This is how the default
+        // Copied from Android KillApplicationHandler in RuntimeInit.java. This is how the default
         // Android handler kills this process.
         Process.killProcess(Process.myPid());
         System.exit(10);
diff --git a/content/public/app/content_browser_manifest.cc b/content/public/app/content_browser_manifest.cc
index 560a74f..3bbec4d 100644
--- a/content/public/app/content_browser_manifest.cc
+++ b/content/public/app/content_browser_manifest.cc
@@ -92,7 +92,7 @@
                   "network.mojom.P2PSocketManager",
                   "network.mojom.MdnsResponder",
                   "network.mojom.URLLoaderFactory",
-                  "resource_coordinator.mojom.ProcessCoordinationUnit",
+                  "performance_manager.mojom.ProcessCoordinationUnit",
                   "viz.mojom.CompositingModeReporter",
                   "viz.mojom.Gpu",
               })
@@ -222,7 +222,7 @@
                   "mojom.ProcessInternalsHandler",
                   "network.mojom.RestrictedCookieManager",
                   "blink.mojom.WebSocketConnector",
-                  "resource_coordinator.mojom.DocumentCoordinationUnit",
+                  "performance_manager.mojom.DocumentCoordinationUnit",
                   "viz.mojom.Gpu"})
           .RequireInterfaceFilterCapability_Deprecated(
               mojom::kRendererServiceName, "navigation:frame", "browser")
diff --git a/content/public/browser/android/compositor.h b/content/public/browser/android/compositor.h
index c8fd681..18a2da2 100644
--- a/content/public/browser/android/compositor.h
+++ b/content/public/browser/android/compositor.h
@@ -83,6 +83,9 @@
   // Composite *without* having modified the layer tree.
   virtual void SetNeedsComposite() = 0;
 
+  // Request a draw and swap even if there is no change to the layer tree.
+  virtual void SetNeedsRedraw() = 0;
+
   // Returns the UI resource provider associated with the compositor.
   virtual ui::UIResourceProvider& GetUIResourceProvider() = 0;
 
diff --git a/content/public/browser/background_sync_parameters.cc b/content/public/browser/background_sync_parameters.cc
index 8405360..67a8a19 100644
--- a/content/public/browser/background_sync_parameters.cc
+++ b/content/public/browser/background_sync_parameters.cc
@@ -23,6 +23,7 @@
 #if defined(OS_ANDROID)
       rely_on_android_network_detection(false),
 #endif
+      keep_browser_awake_till_events_complete(false),
       max_sync_attempts(kMaxSyncAttempts),
       max_sync_attempts_with_notification_permission(kMaxSyncAttempts),
       initial_retry_delay(kInitialRetryDelay),
@@ -32,6 +33,9 @@
       min_periodic_sync_events_interval(kMinPeriodicSyncEventsInterval) {
 }
 
+BackgroundSyncParameters::BackgroundSyncParameters(
+    const BackgroundSyncParameters& other) = default;
+
 bool BackgroundSyncParameters::operator==(
     const BackgroundSyncParameters& other) const {
   return disable == other.disable &&
@@ -39,6 +43,8 @@
          rely_on_android_network_detection ==
              other.rely_on_android_network_detection &&
 #endif
+         keep_browser_awake_till_events_complete ==
+             other.keep_browser_awake_till_events_complete &&
          max_sync_attempts == other.max_sync_attempts &&
          max_sync_attempts_with_notification_permission ==
              other.max_sync_attempts_with_notification_permission &&
diff --git a/content/public/browser/background_sync_parameters.h b/content/public/browser/background_sync_parameters.h
index a8a0286..31a80fc 100644
--- a/content/public/browser/background_sync_parameters.h
+++ b/content/public/browser/background_sync_parameters.h
@@ -15,6 +15,7 @@
 
 struct CONTENT_EXPORT BackgroundSyncParameters {
   BackgroundSyncParameters();
+  BackgroundSyncParameters(const BackgroundSyncParameters& other);
   bool operator==(const BackgroundSyncParameters& other) const;
 
   // True if the manager should be disabled and registration attempts should
@@ -26,6 +27,11 @@
   bool rely_on_android_network_detection;
 #endif
 
+  // If true, we keep the browser awake till all (periodic)sync events fired
+  // have completed. If false, we only keep the browser awake till all ready
+  // (periodic)sync events have been fired.
+  bool keep_browser_awake_till_events_complete;
+
   // The number of attempts the BackgroundSyncManager will make to fire an
   // event before giving up.
   int max_sync_attempts;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 5d80887..76be4fc 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -340,9 +340,10 @@
   // - The default factory to be used by a frame.  In this case
   //   |request_initiator| is the origin being committed in the frame (or the
   //   last origin committed in the frame).
-  // - The initiator-specific factory to be used by a frame.  This happens for
-  //   origins covered via
-  //   RenderFrameHost::MarkInitiatorAsRequiringSeparateURLLoaderFactory.
+  // - An isolated-world-specific factory to be used by a frame.  This happens
+  //   for origins covered via
+  //   RenderFrameHost::MarkIsolatedWorldAsRequiringSeparateURLLoaderFactory.
+  //   In this case |request_initiator| is the origin of the isolated world.
   //
   // This method allows the //content embedder to provide a URLLoaderFactory
   // with |request_initiator|-specific properties (e.g. with relaxed
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index 90847e53..0beaa27 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -357,12 +357,12 @@
       network::mojom::URLLoaderFactoryRequest default_factory_request) = 0;
 
   // Requests that future URLLoaderFactoryBundle(s) sent to the renderer should
-  // use a separate URLLoaderFactory for requests initiated by any of the
-  // origins listed in |request_initiators|.  The URLLoaderFactory(s) for each
+  // use a separate URLLoaderFactory for requests initiated by isolated worlds
+  // listed in |isolated_world_origins|.  The URLLoaderFactory(s) for each
   // origin will be created via
   // ContentBrowserClient::CreateURLLoaderFactoryForNetworkRequests method.
-  virtual void MarkInitiatorsAsRequiringSeparateURLLoaderFactory(
-      base::flat_set<url::Origin> request_initiators,
+  virtual void MarkIsolatedWorldsAsRequiringSeparateURLLoaderFactory(
+      base::flat_set<url::Origin> isolated_world_origins,
       bool push_to_renderer_now) = 0;
 
   // Returns true if the given sandbox flag |flags| is in effect on this frame.
@@ -425,6 +425,10 @@
                                           BrowserControlsState current,
                                           bool animate) = 0;
 
+  // Reloads the frame if it is live. It initiates a reload but doesn't wait for
+  // it to finish.
+  virtual void Reload() = 0;
+
  private:
   // This interface should only be implemented inside content.
   friend class RenderFrameHostImpl;
diff --git a/content/public/browser/site_isolation_policy.cc b/content/public/browser/site_isolation_policy.cc
index f88598c..3723f33 100644
--- a/content/public/browser/site_isolation_policy.cc
+++ b/content/public/browser/site_isolation_policy.cc
@@ -45,6 +45,8 @@
   }
 #endif
 
+  // Check with the embedder.  In particular, chrome/ uses this to disable site
+  // isolation when below a memory threshold.
   return GetContentClient() &&
          GetContentClient()->browser()->ShouldDisableSiteIsolation();
 }
@@ -90,6 +92,16 @@
 
 // static
 bool SiteIsolationPolicy::IsStrictOriginIsolationEnabled() {
+  // If the feature is explicitly enabled by the user (e.g., from
+  // chrome://flags), honor this regardless of checks to disable site isolation
+  // below.  This means this takes precedence over memory thresholds or
+  // switches to disable site isolation.
+  if (base::FeatureList::GetInstance()->IsFeatureOverriddenFromCommandLine(
+          features::kStrictOriginIsolation.name,
+          base::FeatureList::OVERRIDE_ENABLE_FEATURE)) {
+    return true;
+  }
+
   // TODO(wjmaclean): Figure out what should happen when this feature is
   // combined with --isolate-origins.
   if (IsSiteIsolationDisabled())
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 63372ca..49770ae 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -28,9 +28,10 @@
     base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Allows popups during page unloading.
-// TODO(https://crbug.com/937569): Remove this in Chrome 82.
+// TODO(https://crbug.com/1010509): Set to DISABLED_BY_DEFAULT in Chrome 80.
+// TODO(https://crbug.com/937569): Remove this entirely in Chrome 82.
 const base::Feature kAllowPopupsDuringPageUnload{
-    "AllowPopupsDuringPageUnload", base::FEATURE_DISABLED_BY_DEFAULT};
+    "AllowPopupsDuringPageUnload", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Accepts Origin-Signed HTTP Exchanges to be signed with certificates
 // that do not have CanSignHttpExchangesDraft extension.
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h
index c3fd077b..d584847 100644
--- a/content/public/renderer/render_frame.h
+++ b/content/public/renderer/render_frame.h
@@ -20,7 +20,6 @@
 #include "ppapi/buildflags/buildflags.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
-#include "third_party/blink/public/common/loader/url_loader_factory_bundle.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom.h"
 #include "third_party/blink/public/platform/task_type.h"
@@ -32,14 +31,17 @@
 class AssociatedInterfaceProvider;
 class AssociatedInterfaceRegistry;
 class BrowserInterfaceBrokerProxy;
+class WebElement;
 class WebFrame;
 class WebLocalFrame;
 class WebPlugin;
 struct WebPluginParams;
+struct WebRect;
 }
 
 namespace gfx {
 class Range;
+class RectF;
 class Size;
 }
 
@@ -292,16 +294,6 @@
   virtual void SetRenderFrameMediaPlaybackOptions(
       const RenderFrameMediaPlaybackOptions& opts) = 0;
 
-  // Requests that fetches initiated by |initiator_origin| should go through the
-  // provided |url_loader_factory|.  This method should be called before
-  // executing scripts in a isolated world - such scripts are typically
-  // associated with a security origin different from the main world (and
-  // therefore fetches from such scripts set |request_initiator| that is
-  // incompatible with |request_initiator_site_lock|.
-  virtual void MarkInitiatorAsRequiringSeparateURLLoaderFactory(
-      const url::Origin& initiator_origin,
-      network::mojom::URLLoaderFactoryPtr url_loader_factory) = 0;
-
   // Synchronously performs the complete set of document lifecycle phases,
   // including updates to the compositor state and rasterization, then sending
   // a frame to the viz display compositor. Does nothing if RenderFrame is not
@@ -311,6 +303,17 @@
   // Sets that cross browsing instance frame lookup is allowed.
   virtual void SetAllowsCrossBrowsingInstanceFrameLookup() = 0;
 
+  // Returns the bounds of |element| in Window coordinates which are device
+  // scale independent. The bounds have been adjusted to include any
+  // transformations, including page scale. This function will update the layout
+  // if required.
+  virtual gfx::RectF ElementBoundsInWindow(
+      const blink::WebElement& element) = 0;
+
+  // Converts the |rect| to Window coordinates which are device scale
+  // independent.
+  virtual void ConvertViewportToWindow(blink::WebRect* rect) = 0;
+
  protected:
   ~RenderFrame() override {}
 
diff --git a/content/public/renderer/render_view.h b/content/public/renderer/render_view.h
index 87bc425..a7cb641f 100644
--- a/content/public/renderer/render_view.h
+++ b/content/public/renderer/render_view.h
@@ -13,13 +13,10 @@
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "ipc/ipc_sender.h"
-#include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/native_widget_types.h"
 
 namespace blink {
-class WebElement;
 class WebView;
-struct WebRect;
 }  // namespace blink
 
 namespace content {
@@ -90,16 +87,6 @@
   // Returns |renderer_preferences_.accept_languages| value.
   virtual const std::string& GetAcceptLanguages() = 0;
 
-  // Converts the |rect| from Viewport coordinates to Window coordinates.
-  // See blink::WebWidgetClient::convertViewportToWindow for more details.
-  virtual void ConvertViewportToWindowViaWidget(blink::WebRect* rect) = 0;
-
-  // Returns the bounds of |element| in Window coordinates. The bounds have been
-  // adjusted to include any transformations, including page scale.
-  // This function will update the layout if required.
-  virtual gfx::RectF ElementBoundsInWindow(const blink::WebElement& element)
-      = 0;
-
  protected:
   ~RenderView() override {}
 
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 952b2ef..a21a9c2 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -38,6 +38,7 @@
 #include "content/browser/scheduler/browser_task_executor.h"
 #include "content/browser/startup_data_impl.h"
 #include "content/browser/startup_helper.h"
+#include "content/browser/tracing/memory_instrumentation_util.h"
 #include "content/browser/tracing/tracing_controller_impl.h"
 #include "content/public/app/content_main.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -424,6 +425,7 @@
     StartBrowserThreadPool();
     BrowserTaskExecutor::PostFeatureListSetup();
     tracing::InitTracingPostThreadPoolStartAndFeatureList();
+    InitializeBrowserMemoryInstrumentationClient();
   }
 
   auto discardable_shared_memory_manager =
diff --git a/content/public/test/test_renderer_host.h b/content/public/test/test_renderer_host.h
index 66544f2..44f1e456 100644
--- a/content/public/test/test_renderer_host.h
+++ b/content/public/test/test_renderer_host.h
@@ -91,9 +91,6 @@
   // Gives tests access to RenderFrameHostImpl::OnDetach. Destroys |this|.
   virtual void Detach() = 0;
 
-  // Simulates a navigation stopping in the RenderFrameHost.
-  virtual void SimulateNavigationStop() = 0;
-
   // Calls OnBeforeUnloadACK on this RenderFrameHost with the given parameter.
   virtual void SendBeforeUnloadACK(bool proceed) = 0;
 
@@ -102,12 +99,12 @@
   virtual void SimulateSwapOutACK() = 0;
 
   // Set the feature policy header for the RenderFrameHost for test. Currently
-  // this is limited to setting a whitelist for a single feature. This function
+  // this is limited to setting an allowlist for a single feature. This function
   // can be generalized as needed. Setting a header policy should only be done
   // once per navigation of the RFH.
   virtual void SimulateFeaturePolicyHeader(
       blink::mojom::FeaturePolicyFeature feature,
-      const std::vector<url::Origin>& whitelist) = 0;
+      const std::vector<url::Origin>& allowlist) = 0;
 
   // Gets all the console messages requested via
   // RenderFrameHost::AddMessageToConsole in this frame.
diff --git a/content/public/test/web_test_support.h b/content/public/test/web_test_support.h
index e9bfe82..ef0ef2c 100644
--- a/content/public/test/web_test_support.h
+++ b/content/public/test/web_test_support.h
@@ -86,9 +86,6 @@
 // Set the device scale factor and force the compositor to resize.
 void SetDeviceScaleFactor(RenderView* render_view, float factor);
 
-// Get the window to viewport scale.
-float GetWindowToViewportScale(RenderView* render_view);
-
 // Converts |event| from screen coordinates to coordinates used by the widget
 // associated with the |web_widget_test_proxy|.  Returns nullptr if no
 // transformation was necessary (e.g. for a keyboard event OR if widget requires
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 5c2df8c49..50b27ec 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -326,6 +326,8 @@
     "worker/dedicated_worker_host_factory_client.h",
     "worker/embedded_shared_worker_stub.cc",
     "worker/embedded_shared_worker_stub.h",
+    "worker/fetch_client_settings_object_helpers.cc",
+    "worker/fetch_client_settings_object_helpers.h",
     "worker/shared_worker_factory_impl.cc",
     "worker/shared_worker_factory_impl.h",
     "worker/worker_thread_registry.cc",
diff --git a/content/renderer/loader/child_url_loader_factory_bundle.cc b/content/renderer/loader/child_url_loader_factory_bundle.cc
index 6bdea06..3e5a1e8d 100644
--- a/content/renderer/loader/child_url_loader_factory_bundle.cc
+++ b/content/renderer/loader/child_url_loader_factory_bundle.cc
@@ -120,7 +120,7 @@
     : URLLoaderFactoryBundleInfo(
           std::move(base_factories->pending_default_factory()),
           std::move(base_factories->pending_scheme_specific_factories()),
-          std::move(base_factories->pending_initiator_specific_factories()),
+          std::move(base_factories->pending_isolated_world_factories()),
           base_factories->bypass_redirect_checks()) {
   pending_appcache_factory_ =
       std::move(base_factories->pending_appcache_factory());
@@ -132,16 +132,15 @@
     mojo::PendingRemote<network::mojom::URLLoaderFactory>
         pending_appcache_factory,
     SchemeMap pending_scheme_specific_factories,
-    OriginMap pending_initiator_specific_factories,
+    OriginMap pending_isolated_world_factories,
     network::mojom::URLLoaderFactoryPtrInfo direct_network_factory_info,
     mojo::PendingRemote<network::mojom::URLLoaderFactory>
         pending_prefetch_loader_factory,
     bool bypass_redirect_checks)
-    : URLLoaderFactoryBundleInfo(
-          std::move(pending_default_factory),
-          std::move(pending_scheme_specific_factories),
-          std::move(pending_initiator_specific_factories),
-          bypass_redirect_checks),
+    : URLLoaderFactoryBundleInfo(std::move(pending_default_factory),
+                                 std::move(pending_scheme_specific_factories),
+                                 std::move(pending_isolated_world_factories),
+                                 bypass_redirect_checks),
       direct_network_factory_info_(std::move(direct_network_factory_info)),
       pending_prefetch_loader_factory_(
           std::move(pending_prefetch_loader_factory)) {
@@ -157,8 +156,8 @@
   other->pending_appcache_factory_ = std::move(pending_appcache_factory_);
   other->pending_scheme_specific_factories_ =
       std::move(pending_scheme_specific_factories_);
-  other->pending_initiator_specific_factories_ =
-      std::move(pending_initiator_specific_factories_);
+  other->pending_isolated_world_factories_ =
+      std::move(pending_isolated_world_factories_);
   other->direct_network_factory_info_ = std::move(direct_network_factory_info_);
   other->pending_prefetch_loader_factory_ =
       std::move(pending_prefetch_loader_factory_);
@@ -327,7 +326,7 @@
       std::move(default_factory_pending_remote),
       std::move(appcache_factory_pending_remote),
       CloneRemoteMapToPendingRemoteMap(scheme_specific_factories_),
-      CloneRemoteMapToPendingRemoteMap(initiator_specific_factories_),
+      CloneRemoteMapToPendingRemoteMap(isolated_world_factories_),
       std::move(direct_network_factory_info),
       std::move(pending_prefetch_loader_factory), bypass_redirect_checks_);
 }
@@ -359,8 +358,7 @@
   return std::make_unique<ChildURLLoaderFactoryBundleInfo>(
       std::move(pending_default_factory), std::move(pending_appcache_factory),
       BoundRemoteMapToPendingRemoteMap(std::move(scheme_specific_factories_)),
-      BoundRemoteMapToPendingRemoteMap(
-          std::move(initiator_specific_factories_)),
+      BoundRemoteMapToPendingRemoteMap(std::move(isolated_world_factories_)),
       std::move(direct_network_factory_info),
       std::move(pending_prefetch_loader_factory), bypass_redirect_checks_);
 }
diff --git a/content/renderer/loader/child_url_loader_factory_bundle.h b/content/renderer/loader/child_url_loader_factory_bundle.h
index 8831d337..9c0716e 100644
--- a/content/renderer/loader/child_url_loader_factory_bundle.h
+++ b/content/renderer/loader/child_url_loader_factory_bundle.h
@@ -41,7 +41,7 @@
       mojo::PendingRemote<network::mojom::URLLoaderFactory>
           pending_default_network_factory,
       SchemeMap pending_scheme_specific_factories,
-      OriginMap pending_initiator_specific_factories,
+      OriginMap pending_isolated_world_factories,
       network::mojom::URLLoaderFactoryPtrInfo direct_network_factory_info,
       mojo::PendingRemote<network::mojom::URLLoaderFactory>
           pending_prefetch_loader_factory,
diff --git a/content/renderer/loader/tracked_child_url_loader_factory_bundle.cc b/content/renderer/loader/tracked_child_url_loader_factory_bundle.cc
index dcb48aa..479467d 100644
--- a/content/renderer/loader/tracked_child_url_loader_factory_bundle.cc
+++ b/content/renderer/loader/tracked_child_url_loader_factory_bundle.cc
@@ -20,7 +20,7 @@
     mojo::PendingRemote<network::mojom::URLLoaderFactory>
         pending_appcache_factory,
     SchemeMap pending_scheme_specific_factories,
-    OriginMap pending_initiator_specific_factories,
+    OriginMap pending_isolated_world_factories,
     network::mojom::URLLoaderFactoryPtrInfo direct_network_factory_info,
     mojo::PendingRemote<network::mojom::URLLoaderFactory>
         pending_prefetch_loader_factory,
@@ -30,7 +30,7 @@
           std::move(pending_default_factory),
           std::move(pending_appcache_factory),
           std::move(pending_scheme_specific_factories),
-          std::move(pending_initiator_specific_factories),
+          std::move(pending_isolated_world_factories),
           std::move(direct_network_factory_info),
           std::move(pending_prefetch_loader_factory),
           bypass_redirect_checks),
@@ -46,8 +46,8 @@
   other->pending_appcache_factory_ = std::move(pending_appcache_factory_);
   other->pending_scheme_specific_factories_ =
       std::move(pending_scheme_specific_factories_);
-  other->pending_initiator_specific_factories_ =
-      std::move(pending_initiator_specific_factories_);
+  other->pending_isolated_world_factories_ =
+      std::move(pending_isolated_world_factories_);
   other->direct_network_factory_info_ = std::move(direct_network_factory_info_);
   other->pending_prefetch_loader_factory_ =
       std::move(pending_prefetch_loader_factory_);
@@ -88,7 +88,7 @@
       std::move(pending_factories->pending_default_factory()),
       std::move(pending_factories->pending_appcache_factory()),
       std::move(pending_factories->pending_scheme_specific_factories()),
-      std::move(pending_factories->pending_initiator_specific_factories()),
+      std::move(pending_factories->pending_isolated_world_factories()),
       std::move(pending_factories->direct_network_factory_info()),
       std::move(pending_factories->pending_prefetch_loader_factory()),
       std::move(main_thread_host_bundle_clone),
@@ -154,7 +154,7 @@
       std::move(pending_factories->pending_default_factory()),
       std::move(pending_factories->pending_appcache_factory()),
       std::move(pending_factories->pending_scheme_specific_factories()),
-      std::move(pending_factories->pending_initiator_specific_factories()),
+      std::move(pending_factories->pending_isolated_world_factories()),
       std::move(pending_factories->direct_network_factory_info()),
       std::move(pending_factories->pending_prefetch_loader_factory()),
       std::move(main_thread_host_bundle_clone),
@@ -177,7 +177,7 @@
       std::move(pending_factories->pending_default_factory()),
       std::move(pending_factories->pending_appcache_factory()),
       std::move(pending_factories->pending_scheme_specific_factories()),
-      std::move(pending_factories->pending_initiator_specific_factories()),
+      std::move(pending_factories->pending_isolated_world_factories()),
       std::move(pending_factories->direct_network_factory_info()),
       std::move(pending_factories->pending_prefetch_loader_factory()),
       std::move(main_thread_host_bundle_clone),
diff --git a/content/renderer/loader/tracked_child_url_loader_factory_bundle.h b/content/renderer/loader/tracked_child_url_loader_factory_bundle.h
index d75b70c..994f137 100644
--- a/content/renderer/loader/tracked_child_url_loader_factory_bundle.h
+++ b/content/renderer/loader/tracked_child_url_loader_factory_bundle.h
@@ -35,7 +35,7 @@
       mojo::PendingRemote<network::mojom::URLLoaderFactory>
           pending_appcache_factory,
       SchemeMap pending_scheme_specific_factories,
-      OriginMap pending_initiator_specific_factories,
+      OriginMap pending_isolated_world_factories,
       network::mojom::URLLoaderFactoryPtrInfo direct_network_factory_info,
       mojo::PendingRemote<network::mojom::URLLoaderFactory>
           pending_prefetch_loader_factory,
diff --git a/content/renderer/page_properties.cc b/content/renderer/page_properties.cc
index da742ca..5d6237f 100644
--- a/content/renderer/page_properties.cc
+++ b/content/renderer/page_properties.cc
@@ -19,43 +19,6 @@
   screen_metrics_emulator_ = std::move(emulator);
 }
 
-void PageProperties::ConvertViewportToWindow(blink::WebRect* rect) {
-  if (compositor_deps_->IsUseZoomForDSFEnabled()) {
-    float reverse = 1 / GetOriginalScreenInfo().device_scale_factor;
-    // TODO(oshima): We may need to allow pixel precision here as the the
-    // anchor element can be placed at half pixel.
-    gfx::Rect window_rect = gfx::ScaleToEnclosedRect(gfx::Rect(*rect), reverse);
-    rect->x = window_rect.x();
-    rect->y = window_rect.y();
-    rect->width = window_rect.width();
-    rect->height = window_rect.height();
-  }
-}
-
-void PageProperties::ConvertViewportToWindow(blink::WebFloatRect* rect) {
-  if (compositor_deps_->IsUseZoomForDSFEnabled()) {
-    rect->x /= GetOriginalScreenInfo().device_scale_factor;
-    rect->y /= GetOriginalScreenInfo().device_scale_factor;
-    rect->width /= GetOriginalScreenInfo().device_scale_factor;
-    rect->height /= GetOriginalScreenInfo().device_scale_factor;
-  }
-}
-
-void PageProperties::ConvertWindowToViewport(blink::WebFloatRect* rect) {
-  if (compositor_deps_->IsUseZoomForDSFEnabled()) {
-    rect->x *= GetOriginalScreenInfo().device_scale_factor;
-    rect->y *= GetOriginalScreenInfo().device_scale_factor;
-    rect->width *= GetOriginalScreenInfo().device_scale_factor;
-    rect->height *= GetOriginalScreenInfo().device_scale_factor;
-  }
-}
-
-const ScreenInfo& PageProperties::GetOriginalScreenInfo() const {
-  return ScreenMetricsEmulator()
-             ? ScreenMetricsEmulator()->original_screen_info()
-             : GetScreenInfo();
-}
-
 CompositorDependencies* PageProperties::GetCompositorDependencies() {
   return compositor_deps_;
 }
diff --git a/content/renderer/page_properties.h b/content/renderer/page_properties.h
index 5e77d21..0af146e 100644
--- a/content/renderer/page_properties.h
+++ b/content/renderer/page_properties.h
@@ -8,11 +8,6 @@
 #include "content/common/content_export.h"
 #include "content/public/common/screen_info.h"
 
-namespace blink {
-struct WebFloatRect;
-struct WebRect;
-}  // namespace blink
-
 namespace content {
 
 class CompositorDependencies;
@@ -51,13 +46,6 @@
   void SetScreenMetricsEmulator(
       std::unique_ptr<RenderWidgetScreenMetricsEmulator> emulator);
 
-  void ConvertViewportToWindow(blink::WebRect* rect);
-  void ConvertViewportToWindow(blink::WebFloatRect* rect);
-  void ConvertWindowToViewport(blink::WebFloatRect* rect);
-
-  // When emulated, this returns the original (non-emulated) ScreenInfo.
-  const ScreenInfo& GetOriginalScreenInfo() const;
-
   CompositorDependencies* GetCompositorDependencies();
 
  private:
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 930fcf0..63fa8c2 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -109,6 +109,7 @@
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_document_loader.h"
+#include "third_party/blink/public/web/web_frame_widget.h"
 #include "third_party/blink/public/web/web_ime_text_span.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_plugin_container.h"
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index e88b9d3..b8c0046 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1485,7 +1485,7 @@
   auto* web_frame_widget =
       blink::WebFrameWidget::CreateForMainFrame(render_widget, web_frame);
 
-  render_widget->InitForMainFrame(std::move(show_callback), web_frame_widget);
+  render_widget->InitForMainFrame(std::move(show_callback));
   render_view->AttachWebFrameWidget(web_frame_widget);
 
   render_widget->SynchronizeVisualPropertiesFromRenderView(
@@ -3992,18 +3992,6 @@
   }
 }
 
-void RenderFrameImpl::MarkInitiatorAsRequiringSeparateURLLoaderFactory(
-    const url::Origin& initiator_origin,
-    network::mojom::URLLoaderFactoryPtr url_loader_factory) {
-  // Set up |loader_factories_| to be updated by the
-  // UpdateSubresourceLoaderFactories() below.
-  GetLoaderFactoryBundle();
-  auto factory_bundle = std::make_unique<blink::URLLoaderFactoryBundleInfo>();
-  factory_bundle->pending_initiator_specific_factories()[initiator_origin] =
-      url_loader_factory.PassInterface();
-  UpdateSubresourceLoaderFactories(std::move(factory_bundle));
-}
-
 void RenderFrameImpl::BindDevToolsAgent(
     mojo::PendingAssociatedRemote<blink::mojom::DevToolsAgentHost> host,
     mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> receiver) {
@@ -4468,7 +4456,6 @@
     // this "swap out", the pointer is moved off to the side until it is
     // swapped back in. The renderer is then told that the WebFrameWidget is
     // dropped which should remove all reference to this object.
-    render_view_->MakeMainFrameRenderWidgetUndead();
     render_view_->DetachWebFrameWidget();
   } else if (render_widget_) {
     DCHECK(owned_render_widget_);
@@ -5229,8 +5216,7 @@
     // include the device scale factor, but not emulation scale. Here we convert
     // them to DIP coordiates relative to the WindowScreenRect.
     blink::WebRect position_in_window(params.x, params.y, 0, 0);
-    render_view_->page_properties()->ConvertViewportToWindow(
-        &position_in_window);
+    GetLocalRootRenderWidget()->ConvertViewportToWindow(&position_in_window);
     if (render_view_->page_properties()->ScreenMetricsEmulator()) {
       const float scale =
           render_view_->page_properties()->ScreenMetricsEmulator()->scale();
@@ -7632,4 +7618,15 @@
   web_url_loader_factory_override_for_test_ = std::move(factory);
 }
 
+gfx::RectF RenderFrameImpl::ElementBoundsInWindow(
+    const blink::WebElement& element) {
+  blink::WebRect bounding_box_in_window = element.BoundsInViewport();
+  GetLocalRootRenderWidget()->ConvertViewportToWindow(&bounding_box_in_window);
+  return gfx::RectF(bounding_box_in_window);
+}
+
+void RenderFrameImpl::ConvertViewportToWindow(blink::WebRect* rect) {
+  GetLocalRootRenderWidget()->ConvertViewportToWindow(rect);
+}
+
 }  // namespace content
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 2351b4a..c660ae4 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -506,6 +506,8 @@
       const RenderFrameMediaPlaybackOptions& opts) override;
   void UpdateAllLifecyclePhasesAndCompositeForTesting() override;
   void SetAllowsCrossBrowsingInstanceFrameLookup() override;
+  gfx::RectF ElementBoundsInWindow(const blink::WebElement& element) override;
+  void ConvertViewportToWindow(blink::WebRect* rect) override;
 
   // blink::mojom::AutoplayConfigurationClient implementation:
   void AddAutoplayFlags(const url::Origin& origin,
@@ -618,9 +620,6 @@
   void UpdateSubresourceLoaderFactories(
       std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
           subresource_loader_factories) override;
-  void MarkInitiatorAsRequiringSeparateURLLoaderFactory(
-      const url::Origin& initiator_origin,
-      network::mojom::URLLoaderFactoryPtr url_loader_factory) override;
   void BindDevToolsAgent(
       mojo::PendingAssociatedRemote<blink::mojom::DevToolsAgentHost> host,
       mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> receiver)
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 72f8ac2..3ab0873c 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -516,10 +516,7 @@
         page_properties(), params->visual_properties.display_mode,
         /*is_undead=*/true, params->never_visible);
     undead_render_widget_->set_delegate(this);
-    // We intentionally pass in a null webwidget since it shouldn't be needed
-    // for remote frames.
-    undead_render_widget_->InitForMainFrame(std::move(show_callback),
-                                            /*web_frame_widget=*/nullptr);
+    undead_render_widget_->InitForMainFrame(std::move(show_callback));
 
     RenderFrameProxy::CreateFrameProxy(params->proxy_routing_id, GetRoutingID(),
                                        opener_frame, MSG_ROUTING_NONE,
@@ -556,7 +553,6 @@
 
 RenderViewImpl::~RenderViewImpl() {
   DCHECK(destroying_);  // Always deleted through Destroy().
-  DCHECK(!frame_widget_);
 
   g_routing_id_view_map.Get().erase(routing_id_);
   RenderThread::Get()->RemoveRoute(routing_id_);
@@ -1073,13 +1069,8 @@
   // a main frame. So it should not be able to see this happening when there is
   // no local main frame.
   if (close_render_widget_here) {
-    if (undead_render_widget_) {
-      RenderWidget* closing_widget = undead_render_widget_.get();
-      closing_widget->CloseForFrame(std::move(undead_render_widget_));
-    } else {
-      RenderWidget* closing_widget = render_widget_.get();
-      closing_widget->CloseForFrame(std::move(render_widget_));
-    }
+    RenderWidget* closing_widget = undead_render_widget_.get();
+    closing_widget->CloseForFrame(std::move(undead_render_widget_));
   }
 
   delete this;
@@ -1150,7 +1141,8 @@
 
 void RenderViewImpl::ScrollFocusedNodeIntoViewForWidget() {
   if (WebLocalFrame* focused_frame = GetWebView()->FocusedFrame()) {
-    auto* frame_widget = focused_frame->LocalRoot()->FrameWidget();
+    blink::WebFrameWidget* frame_widget =
+        focused_frame->LocalRoot()->FrameWidget();
     frame_widget->ScrollFocusedEditableElementIntoView();
   }
 }
@@ -1548,9 +1540,10 @@
 }
 
 void RenderViewImpl::AttachWebFrameWidget(blink::WebFrameWidget* frame_widget) {
-  // The previous WebFrameWidget must already be detached by CloseForFrame().
-  DCHECK(!frame_widget_);
-  frame_widget_ = frame_widget;
+  // The previous WebFrameWidget must already be detached by
+  // DetachWebFrameWidget().
+  DCHECK(!render_widget_->GetWebWidget());
+
   render_widget_->SetWebWidgetInternal(frame_widget);
 
   // Initialization for the WebFrameWidget that should only occur for the main
@@ -1563,39 +1556,32 @@
 }
 
 void RenderViewImpl::DetachWebFrameWidget() {
-  DCHECK(frame_widget_);
+  // There is a WebFrameWidget previously attached by AttachWebFrameWidget().
+  DCHECK(render_widget_->GetWebWidget());
 
   if (destroying_) {
     // We are inside RenderViewImpl::Destroy() and the main frame is being
     // detached as part of shutdown. So we can destroy the RenderWidget.
 
-    // The RenderWidget will be closed, and it will close the WebWidget stored
-    // in |frame_widget_|. We just want to drop raw pointer here.
-    frame_widget_ = nullptr;
-    if (undead_render_widget_) {
-      RenderWidget* closing_widget = undead_render_widget_.get();
-      closing_widget->CloseForFrame(std::move(undead_render_widget_));
-    } else {
-      RenderWidget* closing_widget = render_widget_.get();
-      closing_widget->CloseForFrame(std::move(render_widget_));
-    }
+    // We pass ownership of |render_widget_| to itself. Grab a raw pointer to
+    // call the Close() method on so we don't have to be a C++ expert to know
+    // whether we will end up with a nullptr where we didn't intend due to order
+    // of execution.
+    RenderWidget* closing_widget = render_widget_.get();
+    closing_widget->CloseForFrame(std::move(render_widget_));
   } else {
     // We are not inside RenderViewImpl::Destroy(), the main frame is being
     // detached and replaced with a remote frame proxy. We can't close the
     // RenderWidget, and it is marked undead instead, but we do need to close
     // the WebFrameWidget and remove it from the RenderWidget.
-
-    RenderWidget* render_widget = render_widget_.get();
-    if (!render_widget)
-      render_widget = undead_render_widget_.get();
-
-    DCHECK(render_widget->IsUndeadOrProvisional());
+    render_widget_->SetIsUndead(true);
     // The WebWidget needs to be closed even though the RenderWidget won't be
-    // here (since it is marked undead instead).
-    frame_widget_->Close();
-    frame_widget_ = nullptr;
+    // closed here (since it is marked undead instead).
+    render_widget_->GetWebWidget()->Close();
     // This just clears the webwidget_internal_ member from RenderWidget.
-    render_widget->SetWebWidgetInternal(nullptr);
+    render_widget_->SetWebWidgetInternal(nullptr);
+
+    undead_render_widget_ = std::move(render_widget_);
   }
 }
 
@@ -1812,16 +1798,14 @@
   return true;
 }
 
-// TODO(https://crbug.com/1010509): Re-enable this in Chrome 80.
 // TODO(https://crbug.com/937569): Remove this in Chrome 82.
 bool RenderViewImpl::AllowPopupsDuringPageUnload() {
-  return true;
-#if 0
+  // The switch version is for enabling via enterprise policy. The feature
+  // version is for enabling via about:flags and Finch policy.
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
   return command_line.HasSwitch(switches::kAllowPopupsDuringPageUnload) ||
          base::FeatureList::IsEnabled(features::kAllowPopupsDuringPageUnload);
-#endif
 }
 
 bool RenderViewImpl::CanUpdateLayout() {
@@ -1862,38 +1846,26 @@
 
 #endif
 
-void RenderViewImpl::ConvertViewportToWindowViaWidget(blink::WebRect* rect) {
-  page_properties_.ConvertViewportToWindow(rect);
-}
-
-gfx::RectF RenderViewImpl::ElementBoundsInWindow(
-    const blink::WebElement& element) {
-  blink::WebRect bounding_box_in_window = element.BoundsInViewport();
-  page_properties_.ConvertViewportToWindow(&bounding_box_in_window);
-  return gfx::RectF(bounding_box_in_window);
-}
-
 void RenderViewImpl::UpdatePreferredSize() {
   // We don't always want to send the change messages over IPC, only if we've
   // been put in that mode by getting a |ViewMsg_EnablePreferredSizeChangedMode|
   // message.
-  if (!send_preferred_size_changes_ || !webview())
+  if (!send_preferred_size_changes_ || !webview() || !main_render_frame_)
     return;
 
   if (!needs_preferred_size_update_)
     return;
   needs_preferred_size_update_ = false;
 
-  blink::WebSize tmp_size = webview()->ContentsPreferredMinimumSize();
-  blink::WebRect tmp_rect(0, 0, tmp_size.width, tmp_size.height);
-  page_properties_.ConvertViewportToWindow(&tmp_rect);
-  gfx::Size size(tmp_rect.width, tmp_rect.height);
-  if (size == preferred_size_)
-    return;
+  blink::WebSize web_size = webview()->ContentsPreferredMinimumSize();
+  blink::WebRect web_rect(0, 0, web_size.width, web_size.height);
+  render_widget_->ConvertViewportToWindow(&web_rect);
+  gfx::Size size(web_rect.width, web_rect.height);
 
-  preferred_size_ = size;
-  Send(new ViewHostMsg_DidContentsPreferredSizeChange(GetRoutingID(),
-                                                      preferred_size_));
+  if (size != preferred_size_) {
+    preferred_size_ = size;
+    Send(new ViewHostMsg_DidContentsPreferredSizeChange(GetRoutingID(), size));
+  }
 }
 
 blink::WebString RenderViewImpl::AcceptLanguages() {
@@ -1957,11 +1929,6 @@
   // does not change when tests override the visibility of the Page.
 }
 
-void RenderViewImpl::MakeMainFrameRenderWidgetUndead() {
-  render_widget_->SetIsUndead(true);
-  undead_render_widget_ = std::move(render_widget_);
-}
-
 void RenderViewImpl::ReviveUndeadMainFrameRenderWidget() {
   render_widget_ = std::move(undead_render_widget_);
   render_widget_->SetIsUndead(false);
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index a2c7a831..e39f9f3b 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -49,7 +49,6 @@
 #include "third_party/blink/public/web/web_ax_object.h"
 #include "third_party/blink/public/web/web_console_message.h"
 #include "third_party/blink/public/web/web_element.h"
-#include "third_party/blink/public/web/web_frame_widget.h"
 #include "third_party/blink/public/web/web_history_item.h"
 #include "third_party/blink/public/web/web_navigation_type.h"
 #include "third_party/blink/public/web/web_node.h"
@@ -61,6 +60,7 @@
 #include "ui/surface/transport_dib.h"
 
 namespace blink {
+class WebFrameWidget;
 class WebURLRequest;
 struct PluginAction;
 struct WebWindowFeatures;
@@ -303,8 +303,6 @@
 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
   virtual void didScrollWithKeyboard(const blink::WebSize& delta);
 #endif
-  void ConvertViewportToWindowViaWidget(blink::WebRect* rect) override;
-  gfx::RectF ElementBoundsInWindow(const blink::WebElement& element) override;
 
   // Please do not add your stuff randomly to the end here. If there is an
   // appropriate section, add it there. If not, there are some random functions
@@ -328,10 +326,8 @@
   // be able to specify |initial_setting| where IPC handlers do not.
   void ApplyPageHidden(bool hidden, bool initial_setting);
 
-  // These functions take the main frame's RenderWidget and to make it
-  // inaccessible for out-of-process main frames and then brings it back
-  // if the main frame comes back into the current process.
-  void MakeMainFrameRenderWidgetUndead();
+  // Instead of creating a new RenderWidget, this revives the undead
+  // RenderWidget for use with a new local main frame.
   void ReviveUndeadMainFrameRenderWidget();
 
  private:
@@ -689,10 +685,6 @@
 
   RenderFrameImpl* main_render_frame_ = nullptr;
 
-  // Note: RenderViewImpl is pulling double duty: it's the RenderWidget for the
-  // "view", but it's also the RenderWidget for the main frame.
-  blink::WebFrameWidget* frame_widget_ = nullptr;
-
 #if defined(OS_ANDROID)
   // Android Specific ----------------------------------------------------------
 
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 1414189..a3eda3f 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -516,9 +516,8 @@
   Init(std::move(show_callback), web_widget);
 }
 
-void RenderWidget::InitForMainFrame(ShowCallback show_callback,
-                                    blink::WebFrameWidget* web_frame_widget) {
-  Init(std::move(show_callback), web_frame_widget);
+void RenderWidget::InitForMainFrame(ShowCallback show_callback) {
+  Init(std::move(show_callback), /*web_frame_widget=*/nullptr);
 }
 
 void RenderWidget::InitForChildLocalRoot(
@@ -538,8 +537,6 @@
   DCHECK(!webwidget_);
   DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
 
-  RenderThreadImpl* render_thread_impl = RenderThreadImpl::current();
-
   input_handler_ = std::make_unique<RenderWidgetInputHandler>(this, this);
 
   LayerTreeView* layer_tree_view = InitializeLayerTreeView();
@@ -550,9 +547,9 @@
   if (web_widget)
     web_widget->SetAnimationHost(layer_tree_view->animation_host());
 
-  blink::scheduler::WebThreadScheduler* main_thread_scheduler = nullptr;
-  if (render_thread_impl)
-    main_thread_scheduler = render_thread_impl->GetWebMainThreadScheduler();
+  blink::scheduler::WebThreadScheduler* main_thread_scheduler =
+      compositor_deps_->GetWebMainThreadScheduler();
+
   blink::scheduler::WebThreadScheduler* compositor_thread_scheduler =
       blink::scheduler::WebThreadScheduler::CompositorThreadScheduler();
   scoped_refptr<base::SingleThreadTaskRunner> compositor_input_task_runner;
@@ -564,6 +561,10 @@
         compositor_thread_scheduler->InputTaskRunner();
   }
 
+  input_event_queue_ = base::MakeRefCounted<MainThreadEventQueue>(
+      this, main_thread_scheduler->InputTaskRunner(), main_thread_scheduler,
+      /*allow_raf_aligned_input=*/!compositor_never_visible_);
+
   // We only use an external input handler for frame RenderWidgets because only
   // frames use the compositor for input handling. Other kinds of RenderWidgets
   // (e.g.  popups, plugins) must forward their input directly through
@@ -1237,7 +1238,7 @@
   // single-thread mode for testing.
   bool record_main_frame_metrics =
       !!compositor_deps_->GetCompositorImplThreadTaskRunner();
-  if (input_event_queue_) {
+  {
     base::Optional<ScopedUkmRafAlignedInputTimer> ukm_timer;
     if (record_main_frame_metrics) {
       ukm_timer.emplace(GetWebWidget());
@@ -1968,16 +1969,6 @@
   if (!is_hidden_ && !is_undead_)
     StartStopCompositor();
 
-  DCHECK_NE(MSG_ROUTING_NONE, routing_id_);
-
-  RenderThreadImpl* render_thread = RenderThreadImpl::current();
-  if (render_thread) {
-    input_event_queue_ = base::MakeRefCounted<MainThreadEventQueue>(
-        this, render_thread->GetWebMainThreadScheduler()->InputTaskRunner(),
-        render_thread->GetWebMainThreadScheduler(),
-        /*allow_raf_aligned_input=*/!compositor_never_visible_);
-  }
-
   return layer_tree_view_.get();
 }
 
@@ -2063,8 +2054,7 @@
 
   // Stop handling main thread input events immediately so we don't have them
   // running while things are partly shut down.
-  if (input_event_queue_)
-    input_event_queue_->ClearClient();
+  input_event_queue_->ClearClient();
 
   // The |webwidget_| will be null when the main frame RenderWidget is undead.
   if (webwidget_)
@@ -2594,15 +2584,34 @@
 }
 
 void RenderWidget::ConvertViewportToWindow(blink::WebRect* rect) {
-  return page_properties_->ConvertViewportToWindow(rect);
+  if (compositor_deps_->IsUseZoomForDSFEnabled()) {
+    float reverse = 1 / GetOriginalScreenInfo().device_scale_factor;
+    // TODO(oshima): We may need to allow pixel precision here as the the
+    // anchor element can be placed at half pixel.
+    gfx::Rect window_rect = gfx::ScaleToEnclosedRect(gfx::Rect(*rect), reverse);
+    rect->x = window_rect.x();
+    rect->y = window_rect.y();
+    rect->width = window_rect.width();
+    rect->height = window_rect.height();
+  }
 }
 
 void RenderWidget::ConvertViewportToWindow(blink::WebFloatRect* rect) {
-  return page_properties_->ConvertViewportToWindow(rect);
+  if (compositor_deps_->IsUseZoomForDSFEnabled()) {
+    rect->x /= GetOriginalScreenInfo().device_scale_factor;
+    rect->y /= GetOriginalScreenInfo().device_scale_factor;
+    rect->width /= GetOriginalScreenInfo().device_scale_factor;
+    rect->height /= GetOriginalScreenInfo().device_scale_factor;
+  }
 }
 
 void RenderWidget::ConvertWindowToViewport(blink::WebFloatRect* rect) {
-  return page_properties_->ConvertWindowToViewport(rect);
+  if (compositor_deps_->IsUseZoomForDSFEnabled()) {
+    rect->x *= GetOriginalScreenInfo().device_scale_factor;
+    rect->y *= GetOriginalScreenInfo().device_scale_factor;
+    rect->width *= GetOriginalScreenInfo().device_scale_factor;
+    rect->height *= GetOriginalScreenInfo().device_scale_factor;
+  }
 }
 
 void RenderWidget::OnRequestTextInputStateUpdate() {
@@ -3375,8 +3384,7 @@
 }
 
 void RenderWidget::SetHasPointerRawUpdateEventHandlers(bool has_handlers) {
-  if (input_event_queue_)
-    input_event_queue_->HasPointerRawUpdateEventHandlers(has_handlers);
+  input_event_queue_->HasPointerRawUpdateEventHandlers(has_handlers);
 }
 
 void RenderWidget::SetHasTouchEventHandlers(bool has_handlers) {
@@ -3394,13 +3402,11 @@
 }
 
 void RenderWidget::SetNeedsLowLatencyInput(bool needs_low_latency) {
-  if (input_event_queue_)
-    input_event_queue_->SetNeedsLowLatency(needs_low_latency);
+  input_event_queue_->SetNeedsLowLatency(needs_low_latency);
 }
 
 void RenderWidget::SetNeedsUnbufferedInputForDebugger(bool unbuffered) {
-  if (input_event_queue_)
-    input_event_queue_->SetNeedsUnbufferedInputForDebugger(unbuffered);
+  input_event_queue_->SetNeedsUnbufferedInputForDebugger(unbuffered);
 }
 
 void RenderWidget::AnimateDoubleTapZoomInMainFrame(
@@ -3675,8 +3681,7 @@
 }
 
 void RenderWidget::RequestUnbufferedInputEvents() {
-  if (input_event_queue_)
-    input_event_queue_->RequestUnbufferedInputEvents();
+  input_event_queue_->RequestUnbufferedInputEvents();
 }
 
 void RenderWidget::SetTouchAction(cc::TouchAction touch_action) {
@@ -3725,7 +3730,9 @@
 }
 
 const ScreenInfo& RenderWidget::GetOriginalScreenInfo() const {
-  return page_properties_->GetOriginalScreenInfo();
+  if (page_properties_->ScreenMetricsEmulator())
+    return page_properties_->ScreenMetricsEmulator()->original_screen_info();
+  return page_properties_->GetScreenInfo();
 }
 
 gfx::PointF RenderWidget::ConvertWindowPointToViewport(
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 13cfd1eb..be5955f0 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -239,9 +239,10 @@
                                blink::WebWidget* web_widget);
 
   // Initialize a new RenderWidget that will be attached to a RenderFrame (via
-  // the WebFrameWidget), for a frame that is a main frame.
-  void InitForMainFrame(ShowCallback show_callback,
-                        blink::WebFrameWidget* web_frame_widget);
+  // the WebFrameWidget), for a frame that is a main frame. At the time of
+  // initialization, the WebWidget is not always available, and it will be set
+  // once the main frame is attached.
+  void InitForMainFrame(ShowCallback show_callback);
 
   // Initialize a new RenderWidget that will be attached to a RenderFrame (via
   // the WebFrameWidget), for a frame that is a local root, but not the main
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index 87e3dc1..7e97b093 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -298,6 +298,8 @@
   widget()->DidChangeCursor(cursor_info);
   EXPECT_EQ(widget()->sink()->message_count(), 0U);
 
+  EXPECT_CALL(*widget()->mock_webwidget(), HandleInputEvent(_))
+      .WillOnce(::testing::Return(blink::WebInputEventResult::kNotHandled));
   widget()->SendInputEvent(SyntheticWebMouseEventBuilder::Build(
                                blink::WebInputEvent::Type::kMouseLeave),
                            HandledEventCallback());
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index 0a6359d1..acbb7ce 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -175,6 +175,16 @@
           ? blink::WebEmbeddedWorkerStartData::kWaitForDebugger
           : blink::WebEmbeddedWorkerStartData::kDontWaitForDebugger;
   start_data->devtools_worker_token = params.devtools_worker_token;
+
+  // TODO(bashi): Consider to have a helper function to convert
+  // mojom::FetchClientSettingsObject to WebFetchClientSettingsObject.
+  start_data->outside_fetch_client_settings_object.referrer_policy =
+      params.outside_fetch_client_settings_object->referrer_policy;
+  start_data->outside_fetch_client_settings_object.outgoing_referrer =
+      params.outside_fetch_client_settings_object->outgoing_referrer;
+  start_data->outside_fetch_client_settings_object.insecure_requests_policy =
+      params.outside_fetch_client_settings_object->insecure_requests_policy;
+
   return start_data;
 }
 
diff --git a/content/renderer/text_input_client_observer.cc b/content/renderer/text_input_client_observer.cc
index 71276f6..ccc9ed5 100644
--- a/content/renderer/text_input_client_observer.cc
+++ b/content/renderer/text_input_client_observer.cc
@@ -21,6 +21,7 @@
 #include "third_party/blink/public/platform/web_rect.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/web/mac/web_substring_util.h"
+#include "third_party/blink/public/web/web_frame_widget.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_view.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/content/renderer/worker/dedicated_worker_host_factory_client.cc b/content/renderer/worker/dedicated_worker_host_factory_client.cc
index f80fe47..94cacc90 100644
--- a/content/renderer/worker/dedicated_worker_host_factory_client.cc
+++ b/content/renderer/worker/dedicated_worker_host_factory_client.cc
@@ -9,6 +9,7 @@
 #include "content/renderer/loader/navigation_response_override_parameters.h"
 #include "content/renderer/loader/web_worker_fetch_context_impl.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
+#include "content/renderer/worker/fetch_client_settings_object_helpers.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h"
@@ -55,20 +56,9 @@
     mojo::ScopedMessagePipeHandle blob_url_token) {
   DCHECK(base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker));
 
-  // TODO(bashi): Create a helper function that converts
-  // WebFetchClientSettingsObject to mojom::FetchClientSettingsObject.
-  auto outside_fetch_client_settings_object =
-      blink::mojom::FetchClientSettingsObject::New();
-  outside_fetch_client_settings_object->referrer_policy =
-      fetch_client_settings_object.referrer_policy;
-  outside_fetch_client_settings_object->outgoing_referrer =
-      fetch_client_settings_object.outgoing_referrer;
-  outside_fetch_client_settings_object->insecure_requests_policy =
-      fetch_client_settings_object.insecure_requests_policy;
-
   factory_->CreateWorkerHostAndStartScriptLoad(
       script_url, script_origin, credentials_mode,
-      std::move(outside_fetch_client_settings_object),
+      FetchClientSettingsObjectFromWebToMojom(fetch_client_settings_object),
       mojo::PendingRemote<blink::mojom::BlobURLToken>(
           std::move(blob_url_token), blink::mojom::BlobURLToken::Version_),
       receiver_.BindNewPipeAndPassRemote(),
diff --git a/content/renderer/worker/fetch_client_settings_object_helpers.cc b/content/renderer/worker/fetch_client_settings_object_helpers.cc
new file mode 100644
index 0000000..7a422d22
--- /dev/null
+++ b/content/renderer/worker/fetch_client_settings_object_helpers.cc
@@ -0,0 +1,20 @@
+// 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 "content/renderer/worker/fetch_client_settings_object_helpers.h"
+
+#include "third_party/blink/public/platform/web_fetch_client_settings_object.h"
+
+namespace content {
+
+blink::mojom::FetchClientSettingsObjectPtr
+FetchClientSettingsObjectFromWebToMojom(
+    const blink::WebFetchClientSettingsObject& web_settings_object) {
+  return blink::mojom::FetchClientSettingsObject::New(
+      web_settings_object.referrer_policy,
+      web_settings_object.outgoing_referrer,
+      web_settings_object.insecure_requests_policy);
+}
+
+}  // namespace content
diff --git a/content/renderer/worker/fetch_client_settings_object_helpers.h b/content/renderer/worker/fetch_client_settings_object_helpers.h
new file mode 100644
index 0000000..b2a505d
--- /dev/null
+++ b/content/renderer/worker/fetch_client_settings_object_helpers.h
@@ -0,0 +1,25 @@
+// 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 CONTENT_RENDERER_WORKER_FETCH_CLIENT_SETTINGS_OBJECT_HELPERS_H_
+#define CONTENT_RENDERER_WORKER_FETCH_CLIENT_SETTINGS_OBJECT_HELPERS_H_
+
+#include "third_party/blink/public/mojom/loader/fetch_client_settings_object.mojom.h"
+
+namespace blink {
+struct WebFetchClientSettingsObject;
+}  // namespace blink
+
+namespace content {
+
+// Helper functions for converting FetchClientSettingsObject variants.
+// TODO(bashi): Remove these helpers when the Onion Soup is done.
+
+blink::mojom::FetchClientSettingsObjectPtr
+FetchClientSettingsObjectFromWebToMojom(
+    const blink::WebFetchClientSettingsObject& web_settings_object);
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_WORKER_FETCH_CLIENT_SETTINGS_OBJECT_HELPERS_H_
diff --git a/content/shell/browser/shell_devtools_bindings.cc b/content/shell/browser/shell_devtools_bindings.cc
index d841057..2ee3232 100644
--- a/content/shell/browser/shell_devtools_bindings.cc
+++ b/content/shell/browser/shell_devtools_bindings.cc
@@ -55,9 +55,17 @@
 }
 
 std::unique_ptr<base::DictionaryValue> BuildObjectForResponse(
-    const net::HttpResponseHeaders* rh) {
+    const net::HttpResponseHeaders* rh,
+    bool success) {
   auto response = std::make_unique<base::DictionaryValue>();
-  response->SetInteger("statusCode", rh ? rh->response_code() : 200);
+  int responseCode = 200;
+  if (rh) {
+    responseCode = rh->response_code();
+  } else if (!success) {
+    // In case of no headers, assume file:// URL and failed to load
+    responseCode = 404;
+  }
+  response->SetInteger("statusCode", responseCode);
 
   auto headers = std::make_unique<base::DictionaryValue>();
   size_t iterator = 0;
@@ -118,7 +126,7 @@
   }
 
   void OnComplete(bool success) override {
-    auto response = BuildObjectForResponse(response_headers_.get());
+    auto response = BuildObjectForResponse(response_headers_.get(), success);
     bindings_->SendMessageAck(request_id_, response.get());
     bindings_->loaders_.erase(bindings_->loaders_.find(this));
   }
diff --git a/content/shell/renderer/web_test/blink_test_runner.cc b/content/shell/renderer/web_test/blink_test_runner.cc
index b6e052c..c134bba 100644
--- a/content/shell/renderer/web_test/blink_test_runner.cc
+++ b/content/shell/renderer/web_test/blink_test_runner.cc
@@ -327,10 +327,6 @@
   content::SetDeviceScaleFactor(render_view(), factor);
 }
 
-float BlinkTestRunner::GetWindowToViewportScale() {
-  return content::GetWindowToViewportScale(render_view());
-}
-
 std::unique_ptr<blink::WebInputEvent>
 BlinkTestRunner::TransformScreenToWidgetCoordinates(
     test_runner::WebWidgetTestProxy* web_widget_test_proxy,
diff --git a/content/shell/renderer/web_test/blink_test_runner.h b/content/shell/renderer/web_test/blink_test_runner.h
index 0a654c0..feeaff1 100644
--- a/content/shell/renderer/web_test/blink_test_runner.h
+++ b/content/shell/renderer/web_test/blink_test_runner.h
@@ -91,7 +91,6 @@
   void SimulateWebContentIndexDelete(const std::string& id) override;
   void SetDeviceScaleFactor(float factor) override;
   void SetDeviceColorSpace(const std::string& name) override;
-  float GetWindowToViewportScale() override;
   std::unique_ptr<blink::WebInputEvent> TransformScreenToWidgetCoordinates(
       test_runner::WebWidgetTestProxy* web_widget_test_proxy,
       const blink::WebInputEvent& event) override;
diff --git a/content/shell/test_runner/event_sender.cc b/content/shell/test_runner/event_sender.cc
index 1211887..053d2a29 100644
--- a/content/shell/test_runner/event_sender.cc
+++ b/content/shell/test_runner/event_sender.cc
@@ -35,6 +35,7 @@
 #include "net/base/filename_util.h"
 #include "third_party/blink/public/platform/url_conversion.h"
 #include "third_party/blink/public/platform/web_coalesced_input_event.h"
+#include "third_party/blink/public/platform/web_float_rect.h"
 #include "third_party/blink/public/platform/web_gesture_event.h"
 #include "third_party/blink/public/platform/web_keyboard_event.h"
 #include "third_party/blink/public/platform/web_pointer_properties.h"
@@ -2009,12 +2010,19 @@
 
   const WebPoint& last_pos =
       current_pointer_state_[kRawMousePointerId].last_pos_;
-  float scale = delegate()->GetWindowToViewportScale();
-  WebFloatPoint scaled_last_pos(last_pos.x * scale, last_pos.y * scale);
+
+  // Compute the scale from window (dsf-independent) to blink (dsf-dependent
+  // under UseZoomForDSF).
+  blink::WebFloatRect rect(0, 0, 1.0f, 0.0);
+  web_widget_test_proxy_->ConvertWindowToViewport(&rect);
+  float scale_to_blink_coords = rect.width;
+
+  WebFloatPoint last_pos_for_blink(last_pos.x * scale_to_blink_coords,
+                                   last_pos.y * scale_to_blink_coords);
 
   // Provide a drag source.
-  mainFrameWidget()->DragTargetDragEnter(current_drag_data_, scaled_last_pos,
-                                         scaled_last_pos,
+  mainFrameWidget()->DragTargetDragEnter(current_drag_data_, last_pos_for_blink,
+                                         last_pos_for_blink,
                                          current_drag_effects_allowed_, 0);
   // |is_drag_mode_| saves events and then replays them later. We don't
   // need/want that.
@@ -2765,10 +2773,16 @@
 
   WebPagePopup* popup = view()->GetPagePopup();
   if (popup && !WebInputEvent::IsKeyboardEventType(raw_event.GetType())) {
+    // Compute the scale from window (dsf-independent) to blink (dsf-dependent
+    // under UseZoomForDSF).
+    blink::WebFloatRect rect(0, 0, 1.0f, 0.0);
+    web_widget_test_proxy_->ConvertWindowToViewport(&rect);
+    float scale_to_blink_coords = rect.width;
+
     // ui::ScaleWebInputEvent returns nullptr when the scale is 1.0f as the
     // event does not have to be converted.
-    std::unique_ptr<WebInputEvent> scaled_event = ui::ScaleWebInputEvent(
-        raw_event, delegate()->GetWindowToViewportScale());
+    std::unique_ptr<WebInputEvent> scaled_event =
+        ui::ScaleWebInputEvent(raw_event, scale_to_blink_coords);
     const WebInputEvent* popup_friendly_event =
         scaled_event.get() ? scaled_event.get() : &raw_event;
     return popup->HandleInputEvent(
diff --git a/content/shell/test_runner/web_test_delegate.h b/content/shell/test_runner/web_test_delegate.h
index 5b41ade..d849432 100644
--- a/content/shell/test_runner/web_test_delegate.h
+++ b/content/shell/test_runner/web_test_delegate.h
@@ -129,11 +129,6 @@
   // Controls the device scale factor of the main WebView for hidpi tests.
   virtual void SetDeviceScaleFactor(float factor) = 0;
 
-  // When use-zoom-for-dsf mode is enabled, this returns the scale to
-  // convert from window coordinates to viewport coordinates. When
-  // use-zoom-for-dsf is disabled, this return always 1.0f.
-  virtual float GetWindowToViewportScale() = 0;
-
   // Converts |event| from screen coordinates used by test_runner::EventSender
   // into coordinates that are understood by the widget associated with
   // |web_widget_test_proxy|.  Returns nullptr if no transformation was
diff --git a/content/shell/test_runner/web_widget_test_proxy.cc b/content/shell/test_runner/web_widget_test_proxy.cc
index 53a2df7..3db5943 100644
--- a/content/shell/test_runner/web_widget_test_proxy.cc
+++ b/content/shell/test_runner/web_widget_test_proxy.cc
@@ -13,6 +13,7 @@
 #include "content/shell/test_runner/web_test_delegate.h"
 #include "content/shell/test_runner/web_test_interfaces.h"
 #include "content/shell/test_runner/web_view_test_proxy.h"
+#include "third_party/blink/public/web/web_frame_widget.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_page_popup.h"
 #include "third_party/blink/public/web/web_view.h"
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index eff69d8..4294491a 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -257,8 +257,6 @@
     "dwrite_font_fake_sender_win.h",
     "fake_compositor_dependencies.cc",
     "fake_compositor_dependencies.h",
-    "fake_leveldb_database.cc",
-    "fake_leveldb_database.h",
     "fake_mojo_message_dispatch_context.h",
     "fake_network.cc",
     "fake_network.h",
@@ -1610,8 +1608,6 @@
     "../browser/dom_storage/session_storage_metadata_unittest.cc",
     "../browser/dom_storage/session_storage_namespace_impl_mojo_unittest.cc",
     "../browser/dom_storage/storage_area_impl_unittest.cc",
-    "../browser/dom_storage/test/fake_leveldb_database_error_on_write.cc",
-    "../browser/dom_storage/test/fake_leveldb_database_error_on_write.h",
     "../browser/dom_storage/test/storage_area_test_util.cc",
     "../browser/dom_storage/test/storage_area_test_util.h",
     "../browser/download/download_manager_impl_unittest.cc",
diff --git a/content/test/data/accessibility/html/table-layout-expected-uia-win.txt b/content/test/data/accessibility/html/table-layout-expected-uia-win.txt
index 8e1396f..a3f279d 100644
--- a/content/test/data/accessibility/html/table-layout-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/table-layout-expected-uia-win.txt
@@ -1,23 +1,23 @@
 document Name='Table example #2'
-++grid Grid.ColumnCount=0 Grid.RowCount=0 Table.RowOrColumnMajor='RowMajor'
+++grid Grid.ColumnCount=3 Grid.RowCount=3 Table.RowOrColumnMajor='RowMajor'
 ++++row
 ++++++gridcell Name='1' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
 ++++++++description Name='1'
-++++++gridcell Name='2' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
+++++++gridcell Name='2' GridItem.Column=1 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
 ++++++++description Name='2'
-++++++gridcell Name='3' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
+++++++gridcell Name='3' GridItem.Column=2 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
 ++++++++description Name='3'
 ++++row
-++++++gridcell Name='4' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
+++++++gridcell Name='4' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=1 GridItem.RowSpan=1
 ++++++++description Name='4'
-++++++gridcell Name='5' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
+++++++gridcell Name='5' GridItem.Column=1 GridItem.ColumnSpan=1 GridItem.Row=1 GridItem.RowSpan=1
 ++++++++description Name='5'
-++++++gridcell Name='6' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
+++++++gridcell Name='6' GridItem.Column=2 GridItem.ColumnSpan=1 GridItem.Row=1 GridItem.RowSpan=1
 ++++++++description Name='6'
 ++++row
-++++++gridcell Name='7' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
+++++++gridcell Name='7' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=2 GridItem.RowSpan=1
 ++++++++description Name='7'
-++++++gridcell Name='8' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
+++++++gridcell Name='8' GridItem.Column=1 GridItem.ColumnSpan=1 GridItem.Row=2 GridItem.RowSpan=1
 ++++++++description Name='8'
-++++++gridcell Name='9' GridItem.Column=0 GridItem.ColumnSpan=1 GridItem.Row=0 GridItem.RowSpan=1
+++++++gridcell Name='9' GridItem.Column=2 GridItem.ColumnSpan=1 GridItem.Row=2 GridItem.RowSpan=1
 ++++++++description Name='9'
diff --git a/content/test/data/back_forward_cache/charset_utf-8.html b/content/test/data/back_forward_cache/charset_utf-8.html
new file mode 100644
index 0000000..45d0440f
--- /dev/null
+++ b/content/test/data/back_forward_cache/charset_utf-8.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+  </head>
+  <body>
+  </body>
+</html>
diff --git a/content/test/data/back_forward_cache/charset_windows-1250.html b/content/test/data/back_forward_cache/charset_windows-1250.html
new file mode 100644
index 0000000..0a0f43ab
--- /dev/null
+++ b/content/test/data/back_forward_cache/charset_windows-1250.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="windows-1250">
+  </head>
+  <body>
+  </body>
+</html>
diff --git a/content/test/fake_leveldb_database.cc b/content/test/fake_leveldb_database.cc
deleted file mode 100644
index 30be9dcd..0000000
--- a/content/test/fake_leveldb_database.cc
+++ /dev/null
@@ -1,241 +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 "content/test/fake_leveldb_database.h"
-
-#include <iterator>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-
-namespace content {
-
-namespace {
-using leveldb::mojom::BatchedOperation;
-using leveldb::mojom::BatchedOperationPtr;
-
-leveldb::mojom::KeyValuePtr CreateKeyValue(std::vector<uint8_t> key,
-                                           std::vector<uint8_t> value) {
-  leveldb::mojom::KeyValuePtr result = leveldb::mojom::KeyValue::New();
-  result->key = std::move(key);
-  result->value = std::move(value);
-  return result;
-}
-
-base::StringPiece AsStringPiece(const std::vector<uint8_t>& data) {
-  return base::StringPiece(reinterpret_cast<const char*>(data.data()),
-                           data.size());
-}
-
-bool StartsWith(const std::vector<uint8_t>& key,
-                const std::vector<uint8_t>& prefix) {
-  return base::StartsWith(AsStringPiece(key), AsStringPiece(prefix),
-                          base::CompareCase::SENSITIVE);
-}
-
-std::vector<uint8_t> successor(std::vector<uint8_t> data) {
-  for (unsigned i = data.size(); i > 0; --i) {
-    if (data[i - 1] < 255) {
-      data[i - 1]++;
-      return data;
-    }
-  }
-  NOTREACHED();
-  return data;
-}
-
-}  // namespace
-
-FakeLevelDBDatabase::FakeLevelDBDatabase(
-    std::map<std::vector<uint8_t>, std::vector<uint8_t>>* mock_data)
-    : mock_data_(*mock_data) {}
-
-FakeLevelDBDatabase::~FakeLevelDBDatabase() {
-  if (destruction_callback_)
-    std::move(destruction_callback_).Run();
-}
-
-void FakeLevelDBDatabase::Put(const std::vector<uint8_t>& key,
-                              const std::vector<uint8_t>& value,
-                              PutCallback callback) {
-  mock_data_[key] = value;
-  std::move(callback).Run(leveldb::mojom::DatabaseError::OK);
-}
-
-void FakeLevelDBDatabase::Delete(const std::vector<uint8_t>& key,
-                                 DeleteCallback callback) {
-  mock_data_.erase(key);
-  std::move(callback).Run(leveldb::mojom::DatabaseError::OK);
-}
-
-void FakeLevelDBDatabase::DeletePrefixed(const std::vector<uint8_t>& key_prefix,
-                                         DeletePrefixedCallback callback) {
-  mock_data_.erase(mock_data_.lower_bound(key_prefix),
-                   mock_data_.lower_bound(successor(key_prefix)));
-  std::move(callback).Run(leveldb::mojom::DatabaseError::OK);
-}
-
-void FakeLevelDBDatabase::RewriteDB(RewriteDBCallback callback) {
-  std::move(callback).Run(leveldb::mojom::DatabaseError::OK);
-}
-
-void FakeLevelDBDatabase::Write(
-    std::vector<leveldb::mojom::BatchedOperationPtr> operations,
-    WriteCallback callback) {
-  // Replace prefix delete and prefix copy with operations first, and then
-  // execute all operations. This models how the leveldb WriteBatch works.
-  for (size_t i = 0; i < operations.size(); ++i) {
-    const auto& op = operations[i];
-    switch (op->type) {
-      case leveldb::mojom::BatchOperationType::PUT_KEY:
-        break;
-      case leveldb::mojom::BatchOperationType::DELETE_KEY:
-        break;
-      case leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY: {
-        std::vector<leveldb::mojom::BatchedOperationPtr> changes;
-        for (auto map_it = mock_data_.lower_bound(op->key);
-             map_it != mock_data_.lower_bound(successor(op->key)); ++map_it) {
-          BatchedOperationPtr item = BatchedOperation::New();
-          item->type = leveldb::mojom::BatchOperationType::DELETE_KEY;
-          item->key = map_it->first;
-          changes.push_back(std::move(item));
-        }
-        size_t diff = changes.size();
-        operations.insert(operations.begin() + i,
-                          std::make_move_iterator(changes.begin()),
-                          std::make_move_iterator(changes.end()));
-        i += diff;
-        continue;
-      }
-      case leveldb::mojom::BatchOperationType::COPY_PREFIXED_KEY: {
-        DCHECK(op->value);
-        std::vector<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>>
-            copy_changes = CopyPrefixedHelper(op->key, *op->value);
-        std::vector<leveldb::mojom::BatchedOperationPtr> changes;
-        for (auto& change : copy_changes) {
-          BatchedOperationPtr item = BatchedOperation::New();
-          item->type = leveldb::mojom::BatchOperationType::PUT_KEY;
-          item->key = std::move(change.first);
-          item->value = std::move(change.second);
-          changes.push_back(std::move(item));
-        }
-        size_t diff = changes.size();
-        operations.insert(operations.begin() + i,
-                          std::make_move_iterator(changes.begin()),
-                          std::make_move_iterator(changes.end()));
-        i += diff;
-        continue;
-      }
-    }
-  }
-
-  for (const auto& op : operations) {
-    switch (op->type) {
-      case leveldb::mojom::BatchOperationType::PUT_KEY:
-        DCHECK(op->value);
-        mock_data_[op->key] = *op->value;
-        break;
-      case leveldb::mojom::BatchOperationType::DELETE_KEY:
-        mock_data_.erase(op->key);
-        break;
-      case leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY:
-        break;
-      case leveldb::mojom::BatchOperationType::COPY_PREFIXED_KEY:
-        break;
-    }
-  }
-
-  std::move(callback).Run(leveldb::mojom::DatabaseError::OK);
-}
-
-void FakeLevelDBDatabase::Get(const std::vector<uint8_t>& key,
-                              GetCallback callback) {
-  if (mock_data_.find(key) != mock_data_.end()) {
-    std::move(callback).Run(leveldb::mojom::DatabaseError::OK, mock_data_[key]);
-  } else {
-    std::move(callback).Run(leveldb::mojom::DatabaseError::NOT_FOUND,
-                            std::vector<uint8_t>());
-  }
-}
-
-void FakeLevelDBDatabase::GetPrefixed(const std::vector<uint8_t>& key_prefix,
-                                      GetPrefixedCallback callback) {
-  std::vector<leveldb::mojom::KeyValuePtr> data;
-  for (const auto& row : mock_data_) {
-    if (StartsWith(row.first, key_prefix)) {
-      data.push_back(CreateKeyValue(row.first, row.second));
-    }
-  }
-  std::move(callback).Run(leveldb::mojom::DatabaseError::OK, std::move(data));
-}
-
-void FakeLevelDBDatabase::GetMany(
-    std::vector<leveldb::mojom::GetManyRequestPtr> keys_or_prefixes,
-    GetManyCallback callback) {
-  std::vector<leveldb::mojom::GetManyResultPtr> data;
-  for (const auto& request : keys_or_prefixes) {
-    leveldb::mojom::GetManyResultPtr result =
-        leveldb::mojom::GetManyResult::New();
-    leveldb::Status status;
-
-    if (request->is_key()) {
-      const auto& key = request->get_key();
-      if (mock_data_.find(key) != mock_data_.end())
-        result->set_key_value(mock_data_[key]);
-      else
-        result->set_status(leveldb::mojom::DatabaseError::NOT_FOUND);
-    } else {
-      const auto& key_prefix = request->get_key_prefix();
-      std::vector<leveldb::mojom::KeyValuePtr> values;
-
-      for (const auto& row : mock_data_) {
-        if (StartsWith(row.first, key_prefix))
-          values.push_back(CreateKeyValue(row.first, row.second));
-      }
-
-      result->set_key_prefix_values(std::move(values));
-    }
-
-    data.push_back(std::move(result));
-  }
-  std::move(callback).Run(std::move(data));
-}
-
-void FakeLevelDBDatabase::CopyPrefixed(
-    const std::vector<uint8_t>& source_key_prefix,
-    const std::vector<uint8_t>& destination_key_prefix,
-    CopyPrefixedCallback callback) {
-  std::vector<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>> changes =
-      CopyPrefixedHelper(source_key_prefix, destination_key_prefix);
-  mock_data_.insert(changes.begin(), changes.end());
-  std::move(callback).Run(leveldb::mojom::DatabaseError::OK);
-}
-
-std::vector<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>>
-FakeLevelDBDatabase::CopyPrefixedHelper(
-    const std::vector<uint8_t>& source_key_prefix,
-    const std::vector<uint8_t>& destination_key_prefix) {
-  size_t source_key_prefix_size = source_key_prefix.size();
-  size_t destination_key_prefix_size = destination_key_prefix.size();
-  std::vector<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>>
-      write_batch;
-  for (auto map_it = mock_data_.lower_bound(source_key_prefix);
-       map_it != mock_data_.lower_bound(successor(source_key_prefix));
-       ++map_it) {
-    size_t excess_key = map_it->first.size() - source_key_prefix_size;
-    std::vector<uint8_t> new_key(destination_key_prefix_size + excess_key);
-    std::copy(destination_key_prefix.begin(), destination_key_prefix.end(),
-              new_key.begin());
-    std::copy(map_it->first.begin() + source_key_prefix_size,
-              map_it->first.end(),
-              new_key.begin() + destination_key_prefix_size);
-    write_batch.emplace_back(std::move(new_key), map_it->second);
-  }
-
-  return write_batch;
-}
-
-}  // namespace content
diff --git a/content/test/fake_leveldb_database.h b/content/test/fake_leveldb_database.h
deleted file mode 100644
index 341cff3..0000000
--- a/content/test/fake_leveldb_database.h
+++ /dev/null
@@ -1,60 +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 CONTENT_TEST_FAKE_LEVELDB_DATABASE_H_
-#define CONTENT_TEST_FAKE_LEVELDB_DATABASE_H_
-
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "components/services/leveldb/public/mojom/leveldb.mojom.h"
-
-namespace content {
-
-// Simple implementation of the leveldb::mojom::LevelDBDatabase interface that
-// is backed by a std::map.
-
-class FakeLevelDBDatabase : public leveldb::mojom::LevelDBDatabase {
- public:
-  // |mock_data| must not be null and must outlive this MockLevelDBDatabase
-  // instance. All callbacks are called synchronously.
-  explicit FakeLevelDBDatabase(
-      std::map<std::vector<uint8_t>, std::vector<uint8_t>>* mock_data);
-  ~FakeLevelDBDatabase() override;
-
-  void SetDestructionCallback(base::OnceClosure callback) {
-    destruction_callback_ = std::move(callback);
-  }
-
-  // LevelDBDatabase:
-  void Put(const std::vector<uint8_t>& key,
-           const std::vector<uint8_t>& value,
-           PutCallback callback) override;
-  void Delete(const std::vector<uint8_t>& key,
-              DeleteCallback callback) override;
-  void DeletePrefixed(const std::vector<uint8_t>& key_prefix,
-                      DeletePrefixedCallback callback) override;
-  void RewriteDB(RewriteDBCallback callback) override;
-  void Write(std::vector<leveldb::mojom::BatchedOperationPtr> operations,
-             WriteCallback callback) override;
-  void Get(const std::vector<uint8_t>& key, GetCallback callback) override;
-  void GetPrefixed(const std::vector<uint8_t>& key_prefix,
-                   GetPrefixedCallback callback) override;
-  void GetMany(std::vector<leveldb::mojom::GetManyRequestPtr> keys_or_prefixes,
-               GetManyCallback callback) override;
-  void CopyPrefixed(const std::vector<uint8_t>& source_key_prefix,
-                    const std::vector<uint8_t>& destination_key_prefix,
-                    CopyPrefixedCallback callback) override;
-
- private:
-  std::vector<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>>
-  CopyPrefixedHelper(const std::vector<uint8_t>& source_key_prefix,
-                     const std::vector<uint8_t>& destination_key_prefix);
-
-  std::map<std::vector<uint8_t>, std::vector<uint8_t>>& mock_data_;
-  base::OnceClosure destruction_callback_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_TEST_FAKE_LEVELDB_DATABASE_H_
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
index 5546cc9..0351080 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
+++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@
 # AUTOGENERATED FILE - DO NOT EDIT
 # SEE roll_webgl_conformance.py
-Current webgl revision 7c4e67ff117d6c640e6dd17989afe2fb7da7eecb
+Current webgl revision 2701c130839edbeb226735b0775966b6423d9e83
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index ea3c31f..966fcd1 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -1341,8 +1341,7 @@
 
 void NavigationSimulatorImpl::StopLoading() {
   CHECK(render_frame_host_);
-  render_frame_host_->OnMessageReceived(
-      FrameHostMsg_DidStopLoading(render_frame_host_->GetRoutingID()));
+  render_frame_host_->SimulateLoadingCompleted();
 }
 
 void NavigationSimulatorImpl::FailLoading(
diff --git a/content/test/test_background_sync_manager.cc b/content/test/test_background_sync_manager.cc
index 6ee1c22..79076ef65 100644
--- a/content/test/test_background_sync_manager.cc
+++ b/content/test/test_background_sync_manager.cc
@@ -100,6 +100,20 @@
   std::move(callback).Run(has_main_frame_provider_host_);
 }
 
+void TestBackgroundSyncManager::FireReadyEvents(
+    blink::mojom::BackgroundSyncType sync_type,
+    bool reschedule,
+    base::OnceClosure callback,
+    std::unique_ptr<BackgroundSyncEventKeepAlive> keepalive) {
+  if (dont_fire_sync_events_) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  std::move(callback));
+  } else {
+    BackgroundSyncManager::FireReadyEvents(
+        sync_type, reschedule, std::move(callback), std::move(keepalive));
+  }
+}
+
 void TestBackgroundSyncManager::StoreDataInBackendContinue(
     int64_t sw_registration_id,
     const url::Origin& origin,
diff --git a/content/test/test_background_sync_manager.h b/content/test/test_background_sync_manager.h
index d40385e..45cf90b 100644
--- a/content/test/test_background_sync_manager.h
+++ b/content/test/test_background_sync_manager.h
@@ -99,6 +99,17 @@
       blink::mojom::BackgroundSyncType sync_type,
       base::Time last_browser_wakeup_for_periodic_sync) override;
 
+  // Override to do not fire any sync events when firing is disabled.
+  void FireReadyEvents(blink::mojom::BackgroundSyncType sync_type,
+                       bool reschedule,
+                       base::OnceClosure callback,
+                       std::unique_ptr<BackgroundSyncEventKeepAlive> keepalive =
+                           nullptr) override;
+
+  void SuspendFiringEvents() { dont_fire_sync_events_ = true; }
+
+  void ResumeFiringEvents() { dont_fire_sync_events_ = false; }
+
  protected:
   // Override to allow delays to be injected by tests.
   void StoreDataInBackend(
@@ -147,6 +158,7 @@
   bool delay_backend_ = false;
   bool has_main_frame_provider_host_ = true;
   bool last_chance_ = false;
+  bool dont_fire_sync_events_ = false;
   base::OnceClosure continuation_;
   DispatchSyncCallback dispatch_sync_callback_;
   DispatchSyncCallback dispatch_periodic_sync_callback_;
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 4422fbe..eda2dbfe 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -219,16 +219,6 @@
   SendNavigateWithParams(&params, was_within_same_document);
 }
 
-void TestRenderFrameHost::SimulateNavigationStop() {
-  if (is_loading()) {
-    OnDidStopLoading();
-  } else {
-    // Even if the RenderFrameHost is not loading, there may still be an
-    // ongoing navigation in the FrameTreeNode. Cancel this one as well.
-    frame_tree_node()->ResetNavigationRequest(false, true);
-  }
-}
-
 void TestRenderFrameHost::SendBeforeUnloadACK(bool proceed) {
   base::TimeTicks now = base::TimeTicks::Now();
   OnBeforeUnloadACK(proceed, now, now);
@@ -241,12 +231,12 @@
 // TODO(loonybear): Add a test for non-bool type PolicyValue.
 void TestRenderFrameHost::SimulateFeaturePolicyHeader(
     blink::mojom::FeaturePolicyFeature feature,
-    const std::vector<url::Origin>& whitelist) {
+    const std::vector<url::Origin>& allowlist) {
   blink::ParsedFeaturePolicy header(1);
   header[0].feature = feature;
   header[0].fallback_value = blink::PolicyValue(false);
   header[0].opaque_value = blink::PolicyValue(false);
-  for (const auto& origin : whitelist) {
+  for (const auto& origin : allowlist) {
     header[0].values.insert(std::pair<url::Origin, blink::PolicyValue>(
         origin, blink::PolicyValue(true)));
   }
@@ -703,4 +693,8 @@
       .InitWithNewPipeAndPassReceiver();
 }
 
+void TestRenderFrameHost::SimulateLoadingCompleted() {
+  OnDidStopLoading();
+}
+
 }  // namespace content
diff --git a/content/test/test_render_frame_host.h b/content/test/test_render_frame_host.h
index 6043237..8fcc648 100644
--- a/content/test/test_render_frame_host.h
+++ b/content/test/test_render_frame_host.h
@@ -82,7 +82,6 @@
   void InitializeRenderFrameIfNeeded() override;
   TestRenderFrameHost* AppendChild(const std::string& frame_name) override;
   void Detach() override;
-  void SimulateNavigationStop() override;
   void SendNavigateWithTransition(int nav_entry_id,
                                   bool did_create_new_entry,
                                   const GURL& url,
@@ -91,7 +90,7 @@
   void SimulateSwapOutACK() override;
   void SimulateFeaturePolicyHeader(
       blink::mojom::FeaturePolicyFeature feature,
-      const std::vector<url::Origin>& whitelist) override;
+      const std::vector<url::Origin>& allowlist) override;
   const std::vector<std::string>& GetConsoleMessages() override;
 
   void SendNavigate(int nav_entry_id,
@@ -208,6 +207,10 @@
     return navigation_requests_;
   }
 
+  // Simulates RenderFrameHost finishing loading and dispatching all relevant
+  // callbacks.
+  void SimulateLoadingCompleted();
+
  protected:
   void SendCommitNavigation(
       mojom::NavigationClient* navigation_client,
diff --git a/content/test/web_test_support.cc b/content/test/web_test_support.cc
index 2b6187c2..ee79a73 100644
--- a/content/test/web_test_support.cc
+++ b/content/test/web_test_support.cc
@@ -114,12 +114,6 @@
   return render_frame_proxy;
 }
 
-float GetWindowToViewportScale(RenderWidget* render_widget) {
-  blink::WebFloatRect rect(0, 0, 1.0f, 0.0);
-  render_widget->ConvertWindowToViewport(&rect);
-  return rect.width;
-}
-
 #if defined(OS_WIN)
 // DirectWrite only has access to %WINDIR%\Fonts by default. For developer
 // side-loading, support kRegisterFontFiles to allow access to additional fonts.
@@ -223,13 +217,6 @@
   render_view_impl->GetWidget()->SetDeviceScaleFactorForTesting(factor);
 }
 
-float GetWindowToViewportScale(RenderView* render_view) {
-  RenderViewImpl* render_view_impl = static_cast<RenderViewImpl*>(render_view);
-  blink::WebFloatRect rect(0, 0, 1.0f, 0.0);
-  render_view_impl->page_properties()->ConvertWindowToViewport(&rect);
-  return rect.width;
-}
-
 std::unique_ptr<blink::WebInputEvent> TransformScreenToWidgetCoordinates(
     test_runner::WebWidgetTestProxy* web_widget_test_proxy,
     const blink::WebInputEvent& event) {
@@ -238,8 +225,13 @@
   RenderWidget* render_widget =
       static_cast<RenderWidget*>(web_widget_test_proxy);
 
+  // Compute the scale from window (dsf-independent) to blink (dsf-dependent
+  // under UseZoomForDSF).
+  blink::WebFloatRect rect(0, 0, 1.0f, 0.0);
+  render_widget->ConvertWindowToViewport(&rect);
+  float scale = rect.width;
+
   blink::WebRect view_rect = render_widget->ViewRect();
-  float scale = GetWindowToViewportScale(render_widget);
   gfx::Vector2d delta(-view_rect.x, -view_rect.y);
   return ui::TranslateAndScaleWebInputEvent(event, delta, scale);
 }
diff --git a/device/vr/buildflags/buildflags.gni b/device/vr/buildflags/buildflags.gni
index fc2f5e7..b958614 100644
--- a/device/vr/buildflags/buildflags.gni
+++ b/device/vr/buildflags/buildflags.gni
@@ -47,10 +47,4 @@
   # TODO(crbug.com/843374): AR should not depend on |enable_vr|.
   enable_arcore = enable_vr && is_android && !is_chromecast &&
                   (current_cpu == "arm" || current_cpu == "arm64")
-
-  # Whether to create AR module as an asynchronous DFM.
-  async_ar = false
-
-  # Whether to create VR module as an asynchronous DFM.
-  async_vr = false
 }
diff --git a/device/vr/isolated_gamepad_data_fetcher.cc b/device/vr/isolated_gamepad_data_fetcher.cc
index 50173f39..55ea0eb 100644
--- a/device/vr/isolated_gamepad_data_fetcher.cc
+++ b/device/vr/isolated_gamepad_data_fetcher.cc
@@ -77,8 +77,9 @@
 
 std::unique_ptr<GamepadDataFetcher>
 IsolatedGamepadDataFetcher::Factory::CreateDataFetcher() {
-  device::mojom::IsolatedXRGamepadProviderPtr provider;
-  factory_->GetIsolatedXRGamepadProvider(mojo::MakeRequest(&provider));
+  mojo::PendingRemote<device::mojom::IsolatedXRGamepadProvider> provider;
+  factory_->GetIsolatedXRGamepadProvider(
+      provider.InitWithNewPipeAndPassReceiver());
   return std::make_unique<IsolatedGamepadDataFetcher>(display_id_,
                                                       std::move(provider));
 }
@@ -89,11 +90,11 @@
 
 IsolatedGamepadDataFetcher::IsolatedGamepadDataFetcher(
     device::mojom::XRDeviceId display_id,
-    device::mojom::IsolatedXRGamepadProviderPtr provider)
+    mojo::PendingRemote<device::mojom::IsolatedXRGamepadProvider> provider)
     : display_id_(display_id) {
   // We bind provider_ on the poling thread, but we're created on the main UI
   // thread.
-  provider_info_ = provider.PassInterface();
+  pending_provider_ = std::move(provider);
 }
 
 IsolatedGamepadDataFetcher::~IsolatedGamepadDataFetcher() = default;
@@ -162,8 +163,8 @@
 }
 
 void IsolatedGamepadDataFetcher::GetGamepadData(bool devices_changed_hint) {
-  if (!provider_ && provider_info_) {
-    provider_.Bind(std::move(provider_info_));
+  if (!provider_ && pending_provider_) {
+    provider_.Bind(std::move(pending_provider_));
   }
 
   // If we don't have a provider, we can't give out data.
diff --git a/device/vr/isolated_gamepad_data_fetcher.h b/device/vr/isolated_gamepad_data_fetcher.h
index 3951140..8402c21 100644
--- a/device/vr/isolated_gamepad_data_fetcher.h
+++ b/device/vr/isolated_gamepad_data_fetcher.h
@@ -8,6 +8,8 @@
 #include "device/gamepad/gamepad_data_fetcher.h"
 #include "device/vr/public/mojom/isolated_xr_service.mojom.h"
 #include "device/vr/vr_device.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace device {
 
@@ -33,7 +35,7 @@
 
   IsolatedGamepadDataFetcher(
       device::mojom::XRDeviceId display_id,
-      device::mojom::IsolatedXRGamepadProviderPtr provider);
+      mojo::PendingRemote<device::mojom::IsolatedXRGamepadProvider> provider);
   ~IsolatedGamepadDataFetcher() override;
 
   GamepadSource source() override;
@@ -49,10 +51,10 @@
   bool have_outstanding_request_ = false;
   std::set<unsigned int> active_gamepads_;
   device::mojom::XRGamepadDataPtr data_;
-  device::mojom::IsolatedXRGamepadProviderPtr
+  mojo::Remote<device::mojom::IsolatedXRGamepadProvider>
       provider_;  // Bound on the polling thread.
-  device::mojom::IsolatedXRGamepadProviderPtrInfo
-      provider_info_;  // Received on the UI thread, bound when polled.
+  mojo::PendingRemote<device::mojom::IsolatedXRGamepadProvider>
+      pending_provider_;  // Received on the UI thread, bound when polled.
 
   DISALLOW_COPY_AND_ASSIGN(IsolatedGamepadDataFetcher);
 };
diff --git a/device/vr/oculus/oculus_device.cc b/device/vr/oculus/oculus_device.cc
index 28050908..62c3ee48 100644
--- a/device/vr/oculus/oculus_device.cc
+++ b/device/vr/oculus/oculus_device.cc
@@ -154,20 +154,20 @@
       return;
     }
 
-    // If we have a pending gamepad provider request when starting the render
-    // loop, post the request over to the render loop to be bound.
-    if (provider_request_) {
+    // If we have a pending gamepad provider receiver when starting the render
+    // loop, post the receiver over to the render loop to be bound.
+    if (provider_receiver_) {
       render_loop_->task_runner()->PostTask(
           FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
                                     base::Unretained(render_loop_.get()),
-                                    std::move(provider_request_)));
+                                    std::move(provider_receiver_)));
     }
 
-    if (overlay_request_) {
+    if (overlay_receiver_) {
       render_loop_->task_runner()->PostTask(
           FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
                                     base::Unretained(render_loop_.get()),
-                                    std::move(overlay_request_)));
+                                    std::move(overlay_receiver_)));
     }
   }
 
@@ -290,30 +290,30 @@
 }
 
 void OculusDevice::GetIsolatedXRGamepadProvider(
-    mojom::IsolatedXRGamepadProviderRequest provider_request) {
-  // We bind the provider_request on the render loop thread, so gamepad data is
+    mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver) {
+  // We bind the provider_receiver on the render loop thread, so gamepad data is
   // updated at the rendering rate.
-  // If we haven't started the render loop yet, postpone binding the request
+  // If we haven't started the render loop yet, postpone binding the receiver
   // until we do.
   if (render_loop_->IsRunning()) {
     render_loop_->task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
                                   base::Unretained(render_loop_.get()),
-                                  std::move(provider_request)));
+                                  std::move(provider_receiver)));
   } else {
-    provider_request_ = std::move(provider_request);
+    provider_receiver_ = std::move(provider_receiver);
   }
 }
 
 void OculusDevice::CreateImmersiveOverlay(
-    mojom::ImmersiveOverlayRequest overlay_request) {
+    mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) {
   if (render_loop_->IsRunning()) {
     render_loop_->task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
                                   base::Unretained(render_loop_.get()),
-                                  std::move(overlay_request)));
+                                  std::move(overlay_receiver)));
   } else {
-    overlay_request_ = std::move(overlay_request);
+    overlay_receiver_ = std::move(overlay_receiver);
   }
 }
 
diff --git a/device/vr/oculus/oculus_device.h b/device/vr/oculus/oculus_device.h
index a44754a..3efe2d8 100644
--- a/device/vr/oculus/oculus_device.h
+++ b/device/vr/oculus/oculus_device.h
@@ -12,6 +12,7 @@
 #include "device/vr/public/mojom/vr_service.mojom.h"
 #include "device/vr/vr_device_base.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "third_party/libovr/src/Include/OVR_CAPI.h"
 
 namespace device {
@@ -52,11 +53,12 @@
 
   // mojom::IsolatedXRGamepadProviderFactory
   void GetIsolatedXRGamepadProvider(
-      mojom::IsolatedXRGamepadProviderRequest provider_request) override;
+      mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver)
+      override;
 
   // XRCompositorHost
   void CreateImmersiveOverlay(
-      mojom::ImmersiveOverlayRequest overlay_request) override;
+      mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) override;
 
   void OnPresentationEnded();
   bool EnsureValidDisplayInfo();
@@ -72,10 +74,10 @@
   mojo::Binding<mojom::XRSessionController> exclusive_controller_binding_;
   mojo::Binding<mojom::IsolatedXRGamepadProviderFactory>
       gamepad_provider_factory_binding_;
-  mojom::IsolatedXRGamepadProviderRequest provider_request_;
+  mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver_;
 
   mojo::Binding<mojom::XRCompositorHost> compositor_host_binding_;
-  mojom::ImmersiveOverlayRequest overlay_request_;
+  mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver_;
 
   base::WeakPtrFactory<OculusDevice> weak_ptr_factory_;
 
diff --git a/device/vr/openvr/openvr_device.cc b/device/vr/openvr/openvr_device.cc
index 3a2ced6..42ed3976 100644
--- a/device/vr/openvr/openvr_device.cc
+++ b/device/vr/openvr/openvr_device.cc
@@ -181,18 +181,18 @@
       return;
     }
 
-    if (provider_request_) {
+    if (provider_receiver_) {
       render_loop_->task_runner()->PostTask(
           FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
                                     base::Unretained(render_loop_.get()),
-                                    std::move(provider_request_)));
+                                    std::move(provider_receiver_)));
     }
 
-    if (overlay_request_) {
+    if (overlay_receiver_) {
       render_loop_->task_runner()->PostTask(
           FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
                                     base::Unretained(render_loop_.get()),
-                                    std::move(overlay_request_)));
+                                    std::move(overlay_receiver_)));
     }
   }
 
@@ -280,26 +280,26 @@
 }
 
 void OpenVRDevice::GetIsolatedXRGamepadProvider(
-    mojom::IsolatedXRGamepadProviderRequest provider_request) {
+    mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver) {
   if (render_loop_->IsRunning()) {
     render_loop_->task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
                                   base::Unretained(render_loop_.get()),
-                                  std::move(provider_request)));
+                                  std::move(provider_receiver)));
   } else {
-    provider_request_ = std::move(provider_request);
+    provider_receiver_ = std::move(provider_receiver);
   }
 }
 
 void OpenVRDevice::CreateImmersiveOverlay(
-    mojom::ImmersiveOverlayRequest overlay_request) {
+    mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) {
   if (render_loop_->IsRunning()) {
     render_loop_->task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
                                   base::Unretained(render_loop_.get()),
-                                  std::move(overlay_request)));
+                                  std::move(overlay_receiver)));
   } else {
-    overlay_request_ = std::move(overlay_request);
+    overlay_receiver_ = std::move(overlay_receiver);
   }
 }
 
diff --git a/device/vr/openvr/openvr_device.h b/device/vr/openvr/openvr_device.h
index d852eea19..8485f2c 100644
--- a/device/vr/openvr/openvr_device.h
+++ b/device/vr/openvr/openvr_device.h
@@ -13,6 +13,7 @@
 #include "device/vr/public/mojom/vr_service.mojom.h"
 #include "device/vr/vr_device_base.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 
 namespace device {
 
@@ -56,11 +57,12 @@
 
   // mojom::IsolatedXRGamepadProviderFactory
   void GetIsolatedXRGamepadProvider(
-      mojom::IsolatedXRGamepadProviderRequest provider_request) override;
+      mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver)
+      override;
 
   // XRCompositorHost
   void CreateImmersiveOverlay(
-      mojom::ImmersiveOverlayRequest overlay_request) override;
+      mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) override;
 
   void OnPresentingControllerMojoConnectionError();
   void OnPresentationEnded();
@@ -76,10 +78,10 @@
 
   mojo::Binding<mojom::IsolatedXRGamepadProviderFactory>
       gamepad_provider_factory_binding_;
-  mojom::IsolatedXRGamepadProviderRequest provider_request_;
+  mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver_;
 
   mojo::Binding<mojom::XRCompositorHost> compositor_host_binding_;
-  mojom::ImmersiveOverlayRequest overlay_request_;
+  mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver_;
 
   base::WeakPtrFactory<OpenVRDevice> weak_ptr_factory_{this};
 
diff --git a/device/vr/openxr/openxr_device.cc b/device/vr/openxr/openxr_device.cc
index 985d7ad7..2d2c95d 100644
--- a/device/vr/openxr/openxr_device.cc
+++ b/device/vr/openxr/openxr_device.cc
@@ -136,18 +136,18 @@
       return;
     }
 
-    if (provider_request_) {
+    if (provider_receiver_) {
       render_loop_->task_runner()->PostTask(
           FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
                                     base::Unretained(render_loop_.get()),
-                                    std::move(provider_request_)));
+                                    std::move(provider_receiver_)));
     }
 
-    if (overlay_request_) {
+    if (overlay_receiver_) {
       render_loop_->task_runner()->PostTask(
           FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
                                     base::Unretained(render_loop_.get()),
-                                    std::move(overlay_request_)));
+                                    std::move(overlay_receiver_)));
     }
   }
 
@@ -217,28 +217,28 @@
 }
 
 void OpenXrDevice::GetIsolatedXRGamepadProvider(
-    mojom::IsolatedXRGamepadProviderRequest provider_request) {
+    mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver) {
   EnsureRenderLoop();
   if (render_loop_->IsRunning()) {
     render_loop_->task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
                                   base::Unretained(render_loop_.get()),
-                                  std::move(provider_request)));
+                                  std::move(provider_receiver)));
   } else {
-    provider_request_ = std::move(provider_request);
+    provider_receiver_ = std::move(provider_receiver);
   }
 }
 
 void OpenXrDevice::CreateImmersiveOverlay(
-    mojom::ImmersiveOverlayRequest overlay_request) {
+    mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) {
   EnsureRenderLoop();
   if (render_loop_->IsRunning()) {
     render_loop_->task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
                                   base::Unretained(render_loop_.get()),
-                                  std::move(overlay_request)));
+                                  std::move(overlay_receiver)));
   } else {
-    overlay_request_ = std::move(overlay_request);
+    overlay_receiver_ = std::move(overlay_receiver);
   }
 }
 
diff --git a/device/vr/openxr/openxr_device.h b/device/vr/openxr/openxr_device.h
index 3f4706c19..e96afea 100644
--- a/device/vr/openxr/openxr_device.h
+++ b/device/vr/openxr/openxr_device.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "device/vr/public/mojom/vr_service.mojom.h"
 #include "device/vr/vr_device_base.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 
 namespace device {
 
@@ -41,11 +42,12 @@
 
   // mojom::IsolatedXRGamepadProviderFactory
   void GetIsolatedXRGamepadProvider(
-      mojom::IsolatedXRGamepadProviderRequest provider_request) override;
+      mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver)
+      override;
 
   // XRCompositorHost
   void CreateImmersiveOverlay(
-      mojom::ImmersiveOverlayRequest overlay_request) override;
+      mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) override;
 
   void EnsureRenderLoop();
 
@@ -60,10 +62,10 @@
 
   mojo::Binding<mojom::IsolatedXRGamepadProviderFactory>
       gamepad_provider_factory_binding_;
-  mojom::IsolatedXRGamepadProviderRequest provider_request_;
+  mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver_;
 
   mojo::Binding<mojom::XRCompositorHost> compositor_host_binding_;
-  mojom::ImmersiveOverlayRequest overlay_request_;
+  mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver_;
 
   base::WeakPtrFactory<OpenXrDevice> weak_ptr_factory_;
 
diff --git a/device/vr/public/mojom/isolated_xr_service.mojom b/device/vr/public/mojom/isolated_xr_service.mojom
index 45cf27b..bd5d9b7 100644
--- a/device/vr/public/mojom/isolated_xr_service.mojom
+++ b/device/vr/public/mojom/isolated_xr_service.mojom
@@ -153,7 +153,8 @@
   // Get the IsolatedXRGamepadProvider for a specific XR runtime API (Oculus, or
   // OpenVR, which are currently the only two that are hosted outside of the
   // browser process).
-  GetIsolatedXRGamepadProvider(IsolatedXRGamepadProvider& provider);
+  GetIsolatedXRGamepadProvider(
+      pending_receiver<IsolatedXRGamepadProvider> provider);
 };
 
 // Represents an overlay that the browser may show on top of or instead of WebXR
@@ -187,7 +188,7 @@
 // obtain an ImmersiveOverlay to show overlay UI.  The obtained overlay will
 // disconnect when presentation ends.
 interface XRCompositorHost {
-  CreateImmersiveOverlay(ImmersiveOverlay& overlay);
+  CreateImmersiveOverlay(pending_receiver<ImmersiveOverlay> overlay);
 };
 
 // Notify the browser process about a set of runtimes.  The browser process
@@ -219,7 +220,7 @@
   // Register a client, and triggers OnDeviceAdded for all available runtimes,
   // followed by OnDevicesEnumerated.
   // Should only be called once.
-  RequestDevices(IsolatedXRRuntimeProviderClient client);
+  RequestDevices(pending_remote<IsolatedXRRuntimeProviderClient> client);
 };
 
 // The main interface for the XR Device Service.
diff --git a/device/vr/public/mojom/vr_service.mojom b/device/vr/public/mojom/vr_service.mojom
index 361143f..3b250a1 100644
--- a/device/vr/public/mojom/vr_service.mojom
+++ b/device/vr/public/mojom/vr_service.mojom
@@ -455,6 +455,15 @@
   GetImmersiveVRDisplayInfo() => (VRDisplayInfo? info);
 
   ExitPresent();
+
+  // Used for the renderer process to indicate that it is throttling frame
+  // requests from the page, and thus it (not the page) is responsible for any
+  // drop in frame rate or delay in posting frames. This is mainly meant to be
+  // informational for the browser process, so that it can decide if or what UI
+  // to show if it seems like the frame rate is too low or has stalled. The
+  // renderer can (and may) still decide to submit frames and that should not be
+  // treated as illegal or clear the throttled state.
+  SetFramesThrottled(bool throttled);
 };
 
 // The interface for the renderer to listen to top level XR events, events that
diff --git a/device/vr/windows/compositor_base.cc b/device/vr/windows/compositor_base.cc
index 3b78103..f8b77b6 100644
--- a/device/vr/windows/compositor_base.cc
+++ b/device/vr/windows/compositor_base.cc
@@ -44,9 +44,7 @@
     : base::Thread("WindowsXRCompositor"),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       webxr_js_time_(kSlidingAverageSize),
-      webxr_gpu_time_(kSlidingAverageSize),
-      gamepad_provider_(this),
-      overlay_binding_(this) {
+      webxr_gpu_time_(kSlidingAverageSize) {
   DCHECK(main_thread_task_runner_);
 }
 
@@ -138,22 +136,22 @@
   webxr_has_pose_ = false;
   presentation_receiver_.reset();
   frame_data_receiver_.reset();
-  gamepad_provider_.Close();
-  overlay_binding_.Close();
+  gamepad_provider_receiver_.reset();
+  overlay_receiver_.reset();
   input_event_listener_ = nullptr;
   StopRuntime();
 }
 
 void XRCompositorCommon::RequestGamepadProvider(
-    mojom::IsolatedXRGamepadProviderRequest request) {
-  gamepad_provider_.Close();
-  gamepad_provider_.Bind(std::move(request));
+    mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> receiver) {
+  gamepad_provider_receiver_.reset();
+  gamepad_provider_receiver_.Bind(std::move(receiver));
 }
 
 void XRCompositorCommon::RequestOverlay(
-    mojom::ImmersiveOverlayRequest request) {
-  overlay_binding_.Close();
-  overlay_binding_.Bind(std::move(request));
+    mojo::PendingReceiver<mojom::ImmersiveOverlay> receiver) {
+  overlay_receiver_.reset();
+  overlay_receiver_.Bind(std::move(receiver));
 
   // WebXR is visible and overlay hidden by default until the overlay overrides
   // this.
@@ -272,7 +270,7 @@
 
   // Kill outstanding overlays:
   overlay_visible_ = false;
-  overlay_binding_.Close();
+  overlay_receiver_.reset();
 
   texture_helper_.SetSourceAndOverlayVisible(false, false);
 
diff --git a/device/vr/windows/compositor_base.h b/device/vr/windows/compositor_base.h
index ed5c04e..397d747 100644
--- a/device/vr/windows/compositor_base.h
+++ b/device/vr/windows/compositor_base.h
@@ -13,7 +13,7 @@
 #include "device/vr/util/fps_meter.h"
 #include "device/vr/util/sliding_average.h"
 #include "device/vr/vr_device.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/platform_handle.h"
@@ -76,8 +76,9 @@
       device::mojom::XREnvironmentIntegrationProviderAssociatedRequest
           environment_provider) final;
 
-  void RequestGamepadProvider(mojom::IsolatedXRGamepadProviderRequest request);
-  void RequestOverlay(mojom::ImmersiveOverlayRequest request);
+  void RequestGamepadProvider(
+      mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> receiver);
+  void RequestOverlay(mojo::PendingReceiver<mojom::ImmersiveOverlay> receiver);
 
  protected:
   virtual bool UsesInputEventing();
@@ -181,8 +182,9 @@
   mojom::IsolatedXRGamepadProvider::RequestUpdateCallback gamepad_callback_;
   mojo::Receiver<mojom::XRPresentationProvider> presentation_receiver_{this};
   mojo::Receiver<mojom::XRFrameDataProvider> frame_data_receiver_{this};
-  mojo::Binding<mojom::IsolatedXRGamepadProvider> gamepad_provider_;
-  mojo::Binding<mojom::ImmersiveOverlay> overlay_binding_;
+  mojo::Receiver<mojom::IsolatedXRGamepadProvider> gamepad_provider_receiver_{
+      this};
+  mojo::Receiver<mojom::ImmersiveOverlay> overlay_receiver_{this};
   mojom::XRVisibilityState visibility_state_ =
       mojom::XRVisibilityState::VISIBLE;
 
diff --git a/device/vr/windows_mixed_reality/mixed_reality_device.cc b/device/vr/windows_mixed_reality/mixed_reality_device.cc
index 1ee2278..14ec664 100644
--- a/device/vr/windows_mixed_reality/mixed_reality_device.cc
+++ b/device/vr/windows_mixed_reality/mixed_reality_device.cc
@@ -108,18 +108,18 @@
       return;
     }
 
-    if (provider_request_) {
+    if (provider_receiver_) {
       render_loop_->task_runner()->PostTask(
           FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
                                     base::Unretained(render_loop_.get()),
-                                    std::move(provider_request_)));
+                                    std::move(provider_receiver_)));
     }
 
-    if (overlay_request_) {
+    if (overlay_receiver_) {
       render_loop_->task_runner()->PostTask(
           FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
                                     base::Unretained(render_loop_.get()),
-                                    std::move(overlay_request_)));
+                                    std::move(overlay_receiver_)));
     }
   }
 
@@ -184,30 +184,30 @@
 }
 
 void MixedRealityDevice::GetIsolatedXRGamepadProvider(
-    mojom::IsolatedXRGamepadProviderRequest provider_request) {
+    mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver) {
   if (!render_loop_)
     CreateRenderLoop();
   if (render_loop_->IsRunning()) {
     render_loop_->task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
                                   base::Unretained(render_loop_.get()),
-                                  std::move(provider_request)));
+                                  std::move(provider_receiver)));
   } else {
-    provider_request_ = std::move(provider_request);
+    provider_receiver_ = std::move(provider_receiver);
   }
 }
 
 void MixedRealityDevice::CreateImmersiveOverlay(
-    mojom::ImmersiveOverlayRequest overlay_request) {
+    mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) {
   if (!render_loop_)
     CreateRenderLoop();
   if (render_loop_->IsRunning()) {
     render_loop_->task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
                                   base::Unretained(render_loop_.get()),
-                                  std::move(overlay_request)));
+                                  std::move(overlay_receiver)));
   } else {
-    overlay_request_ = std::move(overlay_request);
+    overlay_receiver_ = std::move(overlay_receiver);
   }
 }
 
diff --git a/device/vr/windows_mixed_reality/mixed_reality_device.h b/device/vr/windows_mixed_reality/mixed_reality_device.h
index 8b13a54..fd9183a6 100644
--- a/device/vr/windows_mixed_reality/mixed_reality_device.h
+++ b/device/vr/windows_mixed_reality/mixed_reality_device.h
@@ -14,6 +14,7 @@
 #include "device/vr/vr_device_base.h"
 #include "device/vr/windows/compositor_base.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 
 namespace device {
 
@@ -40,11 +41,12 @@
 
   // mojom::IsolatedXRGamepadProviderFactory
   void GetIsolatedXRGamepadProvider(
-      mojom::IsolatedXRGamepadProviderRequest provider_request) override;
+      mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver)
+      override;
 
   // XRCompositorHost
   void CreateImmersiveOverlay(
-      mojom::ImmersiveOverlayRequest overlay_request) override;
+      mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) override;
 
   void CreateRenderLoop();
   void Shutdown();
@@ -58,10 +60,10 @@
 
   mojo::Binding<mojom::IsolatedXRGamepadProviderFactory>
       gamepad_provider_factory_binding_;
-  mojom::IsolatedXRGamepadProviderRequest provider_request_;
+  mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver_;
 
   mojo::Binding<mojom::XRCompositorHost> compositor_host_binding_;
-  mojom::ImmersiveOverlayRequest overlay_request_;
+  mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver_;
 
   mojo::Binding<mojom::XRSessionController> exclusive_controller_binding_;
 
diff --git a/docs/README.md b/docs/README.md
index 9428edf..2072fbe 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -173,6 +173,7 @@
     Capture stack traces on layout test crashes without an attached debugger
 *   [Test Descriptions](testing/test_descriptions.md) - Unit test targets that can be
     built, with associated desciptions.
+*   [Fuzz Testing](../testing/libfuzzer/README.md) - Fuzz testing in Chromium.
 *   [IPC Fuzzer](testing/ipc_fuzzer.md) - Fuzz testing of Chromium IPC interfaces.
 *   [Running Chrome tests with AddressSanitizer (asan) and LeakSanitizer (lsan)](testing/linux_running_asan_tests.md) -
     Run Chrome tests with ASAN and LSAN builds to detect addressability issues and memory leaks.
diff --git a/docs/network_traffic_annotations.md b/docs/network_traffic_annotations.md
index 427eb18e..12514b5 100644
--- a/docs/network_traffic_annotations.md
+++ b/docs/network_traffic_annotations.md
@@ -117,7 +117,7 @@
      the source code has hardcoded that the request goes to Google (e.g. for
      ZeroSuggest), use  `GOOGLE_OWNED_SERVICE`. If the request can go to other
      domains and is perceived as a part of a website rather than a native
-     browser feature, use `WEBSITE`. Use `LOCAL` if the reques is processed
+     browser feature, use `WEBSITE`. Use `LOCAL` if the request is processed
      locally and doesn't go to network, otherwise use `OTHER`. If `OTHER` is
      used, please add plain text description in `destination_other`
      field.
@@ -302,9 +302,9 @@
 ### Waterfall tests
 Two commit queue trybots test traffic annotations on changed files using the
 scripts in `tools/traffic_annotation/scripts`. To run these tests faster and to
-avoid spamming the commit queue if an unforeseen error has happed in downstream
-scripts or tools, they are run in error resilient mode, only on changed files,
-and using heuristics to decide which files to process.
+avoid spamming the commit queue if an unforeseen error has happened in
+downstream scripts or tools, they are run in error resilient mode, only on
+changed files, and using heuristics to decide which files to process.
 An FYI bot runs more detailed tests on the whole repository and with different
 switches, to make sure that the heuristics that trybot tests use and the limited
 scope of tests have not neglected any issues.
@@ -434,4 +434,4 @@
 
 For serialization of network traffic annotation and partial network traffic
 annotation tags, you can use the mutable mojo interfaces defined in
-`/services/network/public/mojom`.
\ No newline at end of file
+`/services/network/public/mojom`.
diff --git a/docs/speed/apk_size_regressions.md b/docs/speed/apk_size_regressions.md
index e69fa61..8b7a7fa 100644
--- a/docs/speed/apk_size_regressions.md
+++ b/docs/speed/apk_size_regressions.md
@@ -106,74 +106,13 @@
 
 ## Step 2: Analyze
 
-### Growth is from Translations
-
- * There is likely nothing that can be done. Translations are expensive.
- * Close as `Won't Fix`.
-
-### Growth is from Native Resources (pak files)
-
- * Ensure `compress="gzip"` or `compress="brotli"` is used for all
-   highly-compressible (e.g. text) resources.
-   * Brotli compresses more but is much slower to decompress. Use brotli only
-     when performance doesn't matter much (e.g. internals pages).
- * Look at the SuperSize reports from the trybot to look for unexpected
-   resources, or unreasonably large symbols.
-
-### Growth is from Images
-
- * Would [a VectorDrawable](https://codereview.chromium.org/2857893003/) be better?
-   * If so, try optimizing it with [avocado](https://bugs.chromium.org/p/chromium/issues/detail?id=982302).
- * Would **lossy** compression make sense (often true for large images)?
-   * Then [use lossy webp](https://codereview.chromium.org/2615243002/).
-   * And omit some densities (e.g. add only an xxhdpi version).
- * Would **near-lossless** compression make sense (try it and see)?
-   * [Use pngquant](https://pngquant.org) to reduce the color depth without a
-     perceptual difference (use one of the GUI tools to compare before/afters).
- * Are the **lossless** images fully optimized?
-   * Use [tools/resources/optimize-png-files.sh](https://cs.chromium.org/chromium/src/tools/resources/optimize-png-files.sh).
-   * There is some [Googler-specific guidance](https://goto.google.com/clank/engineering/best-practices/adding-image-assets) as well.
-
-#### What Build-Time Image Optimizations are There?
- * For non-ninepatch images, `drawable-xxxhdpi` are omitted (they are not
-   perceptibly different from xxhdpi in most cases).
- * For non-ninepatch images within res/ directories (not for .pak file images),
-   they are converted to webp.
-   * Use the `android-binary-size` trybot to see the size of the images as webp,
-     or just build `ChromePublic.apk` and use `unzip -l` to see the size of the
-     images within the built apk.
-
-### Growth is from Native Code
-
- * Look at the SuperSize reports from the trybot to look for unexpected symbols,
-   or unreasonably large symbols.
- * If the diff looks reasonable, close as `Won't Fix`.
- * Otherwise, try to refactor a bit (e.g.
- [move code out of templates](https://bugs.chromium.org/p/chromium/issues/detail?id=716393)).
-   * Use [//tools/binary_size/diagnose_bloat.py](https://chromium.googlesource.com/chromium/src/+/master/tools/binary_size/README.md)
-     or the android-binary-size trybot to spot-check your local changes.
- * If symbols are larger than expected, use the `Disassemble()` feature of
-   `supersize console` to see what is going on.
-
-### Growth is from Java Code
-
- * Look at the SuperSize reports from the trybot to look for unexpected methods.
- * Ensure any new Java deps are as specific as possible.
-
-### Growth is from "other lib size" or "Unknown files size"
-
- * File a bug under [Tools > BinarySize](https://bugs.chromium.org/p/chromium/issues/list?q=component%3ATools%3EBinarySize)
-   with a link to your commit.
-
-### You Would Like Assistance
-
- * Feel free to email [binary-size@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/binary-size).
+See [optimization advice](//docs/speed/binary_size/optimization_advice.md).
 
 ## Step 3: Give Up :/
 
 If you have spent O(days) trying to reduce the size overhead of your patch and
-are pretty sure that your implementation is efficient, then add a comment to the
-bug with the following:
+are pretty sure that your implementation is optimal(ish), then add a comment to
+the bug with the following:
 
 1) A description of where the size is coming from (show that you spent the time
    to understand why your code translated to a large binary size).
diff --git a/docs/speed/binary_size/optimization_advice.md b/docs/speed/binary_size/optimization_advice.md
new file mode 100644
index 0000000..4170e86
--- /dev/null
+++ b/docs/speed/binary_size/optimization_advice.md
@@ -0,0 +1,152 @@
+# Optimizing Chrome's Binary Size
+
+ >
+ > This advice focuses on Android.
+ >
+
+[TOC]
+
+## How To Tell if It's Worth Spending Time on Binary Size?
+
+ * Binary size is a shared resource, and thus its growth is largely due to the
+   tragedy of the commons.
+ * It typically takes about a week of engineering time to reduce Android's
+   binary size by 50kb.
+ * As of 2019, Chrome for Android (arm32) grows by about 100kb per week.
+
+## Optimizing Translations (Strings)
+
+ * Use [Android System strings](https://developer.android.com/reference/android/R.string.html) where appropriate
+ * Ensure that strings in .grd files need to be there. For strings that do
+   not need to be translated, put them directly in source code.
+
+## Optimizing Non-Image Native Resources in .pak Files
+
+ * Ensure `compress="gzip"` or `compress="brotli"` is used for all
+   highly-compressible (e.g. text) resources.
+   * Brotli compresses more but is much slower to decompress. Use brotli only
+     when performance doesn't matter (e.g. internals pages).
+ * Look at the SuperSize reports from the android-binary-size trybot to look for
+   unexpected resources, or unreasonably large symbols.
+
+## Optimizing Images
+
+ * Would a vector image work?
+   * For images used in native code: [VectorIcon](https://chromium.googlesource.com/chromium/src/+/HEAD/components/vector_icons/README.md).
+   * For Android drawables: [VectorDrawable](https://codereview.chromium.org/2857893003/).
+     * Optimize vector drawables with [avocado](https://bugs.chromium.org/p/chromium/issues/detail?id=982302).
+ * Would **lossy** compression make sense (often true for large images)?
+   * If so, [use lossy webp](https://codereview.chromium.org/2615243002/).
+   * And omit some densities (e.g. add only an xxhdpi version).
+ * Would **near-lossless** compression make sense?
+   * This can often reduce size by >50% without a perceptible difference.
+   * [Use pngquant](https://pngquant.org) to try this out (use one of the GUI
+     tools to compare before/after).
+ * Are the **lossless** images fully optimized?
+   * Use [tools/resources/optimize-png-files.sh](https://cs.chromium.org/chromium/src/tools/resources/optimize-png-files.sh).
+   * There is some [Googler-specific guidance](https://goto.google.com/clank/engineering/best-practices/adding-image-assets) as well.
+
+### What Build-Time Image Optimizations are There?
+ * For non-ninepatch images, `drawable-xxxhdpi` are omitted (they are not
+   perceptibly different from xxhdpi in most cases).
+ * For non-ninepatch images within res/ directories (not for .pak file images),
+   they are converted to webp.
+   * Use the `android-binary-size` trybot to see the size of the images as webp,
+     or just build `ChromePublic.apk` and use `unzip -l` to see the size of the
+     images within the built apk.
+
+## Optimizing Code
+
+In most parts of the codebase, you should try to optimize your code for binary
+size rather than performance. Most code runs "fast enough" and only needs to be
+performance-optimized if identified as a hot spot. Individual code size affects
+overall binary size no matter the utility of the code.
+
+What this *could* mean in practice?
+ * Use a linear search over an array rather than a binary search over a sorted
+   one.
+ * Reuse common code rather than writing optimized purpose-specific code.
+
+Practical advice:
+ * When making changes, look at symbol breakdowns with SuperSize reports from
+   the [android-binary-size trybot][size-trybot].
+   * Or use [//tools/binary_size/diagnose_bloat.py][diagnose_bloat] to create
+     diffs locally.
+ * Ensure no symbols exists that are used only by tests.
+ * Be concise with strings used for error handling.
+   * Identical strings throughout the codebase are de-duped. Take advantage of
+     this for error-related strings.
+ * If there's a notable increase in `.data.rel.ro`:
+   * Ensure there are not [excessive relocations][relocations].
+ * If there's a notable increase in `.rodata`:
+   * See if it would make sense to compress large symbols here by moving them to
+     .pak files.
+   * Gut-check that all unique string literals being added are actually useful.
+ * If there's a notable increase in `.text`:
+   * If there are a lot of symbols from C++ templates, try moving functions
+     that don't use template parameters to
+     [non-templated helper functions][template_bloat]).
+     * And extract parts of functions that don't use them into helper functions.
+   * Try to leverage identical-code-folding as much as possible by making the
+     shape of your code consistent.
+     * E.g. Use PODs wherever possible, and especially in containers. They will
+       likely compile down to the same code as other pre-existing PODs.
+       * Try also to use consistent field ordering within PODs.
+     * E.g. a `std::vector` of bare pointers will very likely by ICF'ed, but one
+       that uses smart pointers gets type-specific destructor logic inlined into
+       it.
+     * This advice is especially applicable to generated code.
+   * If symbols are larger than expected, use the `Disassemble()` feature of
+     [`supersize console`][supersize-console] to see what is going on.
+     * Watch out for inlined constructors & destructors. E.g. having parameters
+       that are passed by value forces callers to construct objects before
+       calling.
+       * E.g. For frequently called functions, it can make sense to provide
+         separate `const char *` and `const std::string&` overloads rather than
+         a single `base::StringPiece`.
+
+Android-specific advice:
+ * Prefer fewer large JNI calls over many small JNI calls.
+ * Minimize the use of class initializers (`<clinit>()`).
+   * If R8 cannot determine that they are "trivial", they will prevent
+     inlining of static members on the class.
+   * In C++, static objects are created at compile time, but in Java they
+     are created by executing code within `<clinit>()`. There is often little
+     advantage to initializing class fields statically vs. upon first use.
+ * Don't use default interface methods on interfaces with multiple implementers.
+   * Desugaring causes the methods to be added to every implementor separately.
+   * It's more efficient to use a base class to add default methods.
+ * Use config-specific resource directories sparingly.
+   * Introducing a new config has [a large cost][arsc-bloat].
+ * Use `String.format()` instead of concatenation.
+   * Concatenation causes a lot of StringBuilder code to be generated.
+ * Try to use default values for fields rather than explicit initialization.
+   * E.g. Name booleans such that they start as "false".
+   * E.g. Use integer sentinels that have initial state as 0.
+ * Minimize the number of callbacks / lambdas that each API requires.
+   * Each callback / lambda is syntactic sugar for an anonymous class, and all
+     classes have a constructor in addition to the callback method.
+   * E.g. rather than have `onFailure()` vs `onSuccess()`, have an
+     `onFinished(bool)`.
+   * E.g. rather than have `onTextChanged()`, `onDateChanged()`, ..., have a
+     single `onChanged()` that assumes everything changed.
+
+[size-trybot]: //tools/binary_size/README.md#Binary-Size-Trybot-android_binary_size
+[diagnose_bloat]: //tools/binary_size/README.md#diagnose_bloat_py
+[relocations]: //docs/native_relocations.md
+[template_bloat]: https://bugs.chromium.org/p/chromium/issues/detail?id=716393
+[supersize-console]: //tools/binary_size/README.md#Usage_console
+[arsc-bloat]: https://medium.com/androiddevelopers/smallerapk-part-3-removing-unused-resources-1511f9e3f761#0b72
+
+## Optimizing Third-Party Android Dependencies
+
+ * Look through SuperSize symbols to see whether unwanted functionality
+   is being pulled in.
+   * Use ProGuard's `-whyareyoukeeping` to see why unwanted symbols are kept.
+   * Try adding `-assumenosideeffects` rules to strip out unwanted calls.
+ * Consider removing all resources via `strip_resources = true`.
+ * Remove specific drawables via `resource_blacklist_regex`.
+
+## Size Optimization Help
+
+ * Feel free to email [binary-size@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/binary-size).
diff --git a/extensions/browser/api/automation_internal/automation_event_router.cc b/extensions/browser/api/automation_internal/automation_event_router.cc
index 67f6b21..f6ca3209 100644
--- a/extensions/browser/api/automation_internal/automation_event_router.cc
+++ b/extensions/browser/api/automation_internal/automation_event_router.cc
@@ -15,7 +15,6 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_process_host.h"
 #include "extensions/browser/api/automation_internal/automation_internal_api_delegate.h"
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/event_router.h"
diff --git a/extensions/browser/api/automation_internal/automation_event_router.h b/extensions/browser/api/automation_internal/automation_event_router.h
index 977d378..a9fd1e4 100644
--- a/extensions/browser/api/automation_internal/automation_event_router.h
+++ b/extensions/browser/api/automation_internal/automation_event_router.h
@@ -12,6 +12,7 @@
 #include "base/memory/singleton.h"
 #include "base/scoped_observer.h"
 #include "content/public/browser/ax_event_notification_details.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_process_host_observer.h"
 #include "extensions/browser/api/automation_internal/automation_event_router_interface.h"
 #include "extensions/common/api/automation_internal.h"
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index 4b69ca49..3e73eef 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -838,10 +838,10 @@
   // factories are pushed slightly later - during the commit.
   constexpr bool kPushToRendererNow = false;
 
-  // |request_initiator| in fetches initiated by content scripts should use the
-  // origin of the <webview> embedder.
+  // Content scripts run in an isolated world associated with the origin of the
+  // <webview> embedder.
   navigation_handle->GetRenderFrameHost()
-      ->MarkInitiatorsAsRequiringSeparateURLLoaderFactory(
+      ->MarkIsolatedWorldsAsRequiringSeparateURLLoaderFactory(
           {owner_web_contents()->GetMainFrame()->GetLastCommittedOrigin()},
           kPushToRendererNow);
 }
diff --git a/extensions/browser/url_loader_factory_manager.cc b/extensions/browser/url_loader_factory_manager.cc
index ebd09d3..041c07d6 100644
--- a/extensions/browser/url_loader_factory_manager.cc
+++ b/extensions/browser/url_loader_factory_manager.cc
@@ -341,12 +341,12 @@
   return factory_info;
 }
 
-void MarkInitiatorsAsRequiringSeparateURLLoaderFactory(
+void MarkIsolatedWorldsAsRequiringSeparateURLLoaderFactory(
     content::RenderFrameHost* frame,
     std::vector<url::Origin> request_initiators,
     bool push_to_renderer_now) {
   DCHECK(!request_initiators.empty());
-  frame->MarkInitiatorsAsRequiringSeparateURLLoaderFactory(
+  frame->MarkIsolatedWorldsAsRequiringSeparateURLLoaderFactory(
       std::move(request_initiators), push_to_renderer_now);
 }
 
@@ -480,7 +480,7 @@
     // factories are pushed slightly later - during the commit.
     constexpr bool kPushToRendererNow = false;
 
-    MarkInitiatorsAsRequiringSeparateURLLoaderFactory(
+    MarkIsolatedWorldsAsRequiringSeparateURLLoaderFactory(
         frame, std::move(initiators_requiring_separate_factory),
         kPushToRendererNow);
   }
@@ -511,7 +511,7 @@
   // legacy IPC pipe (raciness will be introduced if that ever changes).
   constexpr bool kPushToRendererNow = true;
 
-  MarkInitiatorsAsRequiringSeparateURLLoaderFactory(
+  MarkIsolatedWorldsAsRequiringSeparateURLLoaderFactory(
       frame, {url::Origin::Create(extension->url())}, kPushToRendererNow);
 }
 
@@ -542,7 +542,7 @@
       registry->enabled_extensions().GetByID(precursor_origin.host());
   if (!extension) {
     // This may happen if an extension gets disabled between the time
-    // RenderFrameHost::MarkInitiatorAsRequiringSeparateURLLoaderFactory is
+    // RenderFrameHost::MarkIsolatedWorldAsRequiringSeparateURLLoaderFactory is
     // called and the time
     // ContentBrowserClient::CreateURLLoaderFactory is called.
     return network::mojom::URLLoaderFactoryPtrInfo();
diff --git a/extensions/renderer/DEPS b/extensions/renderer/DEPS
index d2a13a7..134cab9 100644
--- a/extensions/renderer/DEPS
+++ b/extensions/renderer/DEPS
@@ -5,10 +5,6 @@
   "+gin",
   "+net/base/backoff_entry.h",
 
-  # For net::LOAD_MAYBE_USER_GESTURE. Will be removed as
-  # per crbug.com/516495
-  "+net/base/load_flags.h",
-
   "+third_party/skia/include/core",
   "+third_party/cld_3",
 
diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc
index 87c7a19..901b784 100644
--- a/extensions/renderer/extension_frame_helper.cc
+++ b/extensions/renderer/extension_frame_helper.cc
@@ -509,8 +509,7 @@
       render_frame()->GetWebFrame()->GetDocument().DraggableRegions();
   std::vector<DraggableRegion> regions;
   for (blink::WebDraggableRegion& webregion : webregions) {
-    render_frame()->GetRenderView()->ConvertViewportToWindowViaWidget(
-        &webregion.bounds);
+    render_frame()->ConvertViewportToWindow(&webregion.bounds);
 
     regions.push_back(DraggableRegion());
     DraggableRegion& region = regions.back();
diff --git a/extensions/renderer/extension_throttle_entry.cc b/extensions/renderer/extension_throttle_entry.cc
index 199473b..a48fd7c 100644
--- a/extensions/renderer/extension_throttle_entry.cc
+++ b/extensions/renderer/extension_throttle_entry.cc
@@ -13,7 +13,6 @@
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
-#include "net/base/load_flags.h"
 
 namespace extensions {
 
@@ -44,34 +43,24 @@
 const int ExtensionThrottleEntry::kDefaultEntryLifetimeMs = 2 * 60 * 1000;
 
 ExtensionThrottleEntry::ExtensionThrottleEntry(const std::string& url_id)
-    : ExtensionThrottleEntry(url_id, false) {}
-
-ExtensionThrottleEntry::ExtensionThrottleEntry(
-    const std::string& url_id,
-    bool ignore_user_gesture_load_flag_for_tests)
     : sliding_window_period_(
           base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)),
       max_send_threshold_(kDefaultMaxSendThreshold),
       is_backoff_disabled_(false),
       backoff_entry_(&backoff_policy_),
-      url_id_(url_id),
-      ignore_user_gesture_load_flag_for_tests_(
-          ignore_user_gesture_load_flag_for_tests) {
+      url_id_(url_id) {
   Initialize();
 }
 
 ExtensionThrottleEntry::ExtensionThrottleEntry(
     const std::string& url_id,
-    const net::BackoffEntry::Policy* backoff_policy,
-    bool ignore_user_gesture_load_flag_for_tests)
+    const net::BackoffEntry::Policy* backoff_policy)
     : sliding_window_period_(
           base::TimeDelta::FromMilliseconds(kDefaultSlidingWindowPeriodMs)),
       max_send_threshold_(kDefaultMaxSendThreshold),
       is_backoff_disabled_(false),
       backoff_entry_(&backoff_policy_),
-      url_id_(url_id),
-      ignore_user_gesture_load_flag_for_tests_(
-          ignore_user_gesture_load_flag_for_tests) {
+      url_id_(url_id) {
   DCHECK_GE(backoff_policy->initial_delay_ms, 0);
   DCHECK_GT(backoff_policy->multiply_factor, 0);
   DCHECK_GE(backoff_policy->jitter_factor, 0.0);
@@ -97,15 +86,10 @@
   is_backoff_disabled_ = true;
 }
 
-bool ExtensionThrottleEntry::ShouldRejectRequest(int request_load_flags) const {
-  bool reject_request = false;
-  if (!is_backoff_disabled_ &&
-      (ignore_user_gesture_load_flag_for_tests_ ||
-       !ExplicitUserRequest(request_load_flags)) &&
-      GetBackoffEntry()->ShouldRejectRequest()) {
-    reject_request = true;
-  }
-  return reject_request;
+bool ExtensionThrottleEntry::ShouldRejectRequest() const {
+  if (is_backoff_disabled_)
+    return false;
+  return GetBackoffEntry()->ShouldRejectRequest();
 }
 
 int64_t ExtensionThrottleEntry::ReserveSendingTimeForNextRequest(
@@ -226,9 +210,4 @@
   return &backoff_entry_;
 }
 
-// static
-bool ExtensionThrottleEntry::ExplicitUserRequest(const int load_flags) {
-  return (load_flags & net::LOAD_MAYBE_USER_GESTURE) != 0;
-}
-
 }  // namespace extensions
diff --git a/extensions/renderer/extension_throttle_entry.h b/extensions/renderer/extension_throttle_entry.h
index 9699ce9..dcd76a6 100644
--- a/extensions/renderer/extension_throttle_entry.h
+++ b/extensions/renderer/extension_throttle_entry.h
@@ -57,17 +57,11 @@
   // |url_id| is a unique entry ID.
   explicit ExtensionThrottleEntry(const std::string& url_id);
 
-  // Same as above, but exposes the option to ignore
-  // net::LOAD_MAYBE_USER_GESTURE flag of the request.
-  ExtensionThrottleEntry(const std::string& url_id,
-                         bool ignore_user_gesture_load_flag_for_tests);
-
   // The life span of instances created with this constructor is set to
   // infinite, and the number of initial errors to ignore is set to 0.
   // It is only used by unit tests.
   ExtensionThrottleEntry(const std::string& url_id,
-                         const net::BackoffEntry::Policy* backoff_policy,
-                         bool ignore_user_gesture_load_flag_for_tests);
+                         const net::BackoffEntry::Policy* backoff_policy);
 
   virtual ~ExtensionThrottleEntry();
 
@@ -79,15 +73,8 @@
   void DisableBackoffThrottling();
 
   // Returns true when we have encountered server errors and are doing
-  // exponential back-off, unless |request_load_flags| indicates the
-  // request is likely to be user-initiated, or the NetworkDelegate returns
-  // false for |CanThrottleRequest(request)|.
-  //
-  // URLRequestHttpJob checks this method prior to every request; it
-  // cancels requests if this method returns true.
-  //
-  // Note: See load_flags.h for more detail on |request_load_flags|.
-  bool ShouldRejectRequest(int request_load_flags) const;
+  // exponential back-off.
+  bool ShouldRejectRequest() const;
 
   // Calculates a recommended sending time for the next request and reserves it.
   // The sending time is not earlier than the current exponential back-off
@@ -133,11 +120,6 @@
   virtual const net::BackoffEntry* GetBackoffEntry() const;
   virtual net::BackoffEntry* GetBackoffEntry();
 
-  // Returns true if |load_flags| contains a flag that indicates an
-  // explicit request by the user to load the resource. We never
-  // throttle requests with such load flags.
-  static bool ExplicitUserRequest(const int load_flags);
-
   // Used by tests.
   base::TimeTicks sliding_window_release_time() const {
     return sliding_window_release_time_;
@@ -173,8 +155,6 @@
   // Canonicalized URL string that this entry is for; used for logging only.
   const std::string url_id_;
 
-  bool ignore_user_gesture_load_flag_for_tests_;
-
   DISALLOW_COPY_AND_ASSIGN(ExtensionThrottleEntry);
 };
 
diff --git a/extensions/renderer/extension_throttle_manager.cc b/extensions/renderer/extension_throttle_manager.cc
index 07d3bb8a..854ffd88 100644
--- a/extensions/renderer/extension_throttle_manager.cc
+++ b/extensions/renderer/extension_throttle_manager.cc
@@ -23,8 +23,7 @@
 const unsigned int ExtensionThrottleManager::kRequestsBetweenCollecting = 200;
 
 ExtensionThrottleManager::ExtensionThrottleManager()
-    : requests_since_last_gc_(0),
-      ignore_user_gesture_load_flag_for_tests_(false) {
+    : requests_since_last_gc_(0) {
   url_id_replacements_.ClearPassword();
   url_id_replacements_.ClearUsername();
   url_id_replacements_.ClearQuery();
@@ -68,12 +67,10 @@
   // Create the entry if needed.
   if (!entry) {
     if (backoff_policy_for_tests_) {
-      entry.reset(
-          new ExtensionThrottleEntry(url_id, backoff_policy_for_tests_.get(),
-                                     ignore_user_gesture_load_flag_for_tests_));
+      entry = std::make_unique<ExtensionThrottleEntry>(
+          url_id, backoff_policy_for_tests_.get());
     } else {
-      entry.reset(new ExtensionThrottleEntry(
-          url_id, ignore_user_gesture_load_flag_for_tests_));
+      entry = std::make_unique<ExtensionThrottleEntry>(url_id);
     }
 
     // We only disable back-off throttling on an entry that we have
@@ -90,16 +87,13 @@
   return entry.get();
 }
 
-bool ExtensionThrottleManager::ShouldRejectRequest(const GURL& request_url,
-                                                   int request_load_flags) {
+bool ExtensionThrottleManager::ShouldRejectRequest(const GURL& request_url) {
   base::AutoLock auto_lock(lock_);
-  return RegisterRequestUrl(request_url)
-      ->ShouldRejectRequest(request_load_flags);
+  return RegisterRequestUrl(request_url)->ShouldRejectRequest();
 }
 
 bool ExtensionThrottleManager::ShouldRejectRedirect(
     const GURL& request_url,
-    int request_load_flags,
     const net::RedirectInfo& redirect_info) {
   {
     // An entry GC when requests are outstanding can purge entries so check
@@ -109,7 +103,7 @@
     if (it != url_entries_.end())
       it->second->UpdateWithResponse(redirect_info.status_code);
   }
-  return ShouldRejectRequest(redirect_info.new_url, request_load_flags);
+  return ShouldRejectRequest(redirect_info.new_url);
 }
 
 void ExtensionThrottleManager::WillProcessResponse(
@@ -151,12 +145,6 @@
   url_entries_.erase(url_id);
 }
 
-void ExtensionThrottleManager::SetIgnoreUserGestureLoadFlagForTests(
-    bool ignore_user_gesture_load_flag_for_tests) {
-  base::AutoLock auto_lock(lock_);
-  ignore_user_gesture_load_flag_for_tests_ = true;
-}
-
 void ExtensionThrottleManager::SetOnline(bool is_online) {
   // When we switch from online to offline or change IP addresses, we
   // clear all back-off history. This is a precaution in case the change in
diff --git a/extensions/renderer/extension_throttle_manager.h b/extensions/renderer/extension_throttle_manager.h
index 068cf44..f22c99cc 100644
--- a/extensions/renderer/extension_throttle_manager.h
+++ b/extensions/renderer/extension_throttle_manager.h
@@ -49,15 +49,12 @@
   std::unique_ptr<blink::URLLoaderThrottle> MaybeCreateURLLoaderThrottle(
       const blink::WebURLRequest& request);
 
-  // Determine if a request to |request_url| with the given |request_load_flags|
-  // (see net/base/load_flags.h) should be rejected.
-  bool ShouldRejectRequest(const GURL& request_url, int request_load_flags);
+  // Determine if a request to |request_url| should be rejected.
+  bool ShouldRejectRequest(const GURL& request_url);
 
-  // Determine if a redirect from the original |request_url| with the original
-  // |request_load_flags| (see net/base/load_flags.h) should be allowed to be
-  // redirected as specified by |redirect_info|.
+  // Determine if a redirect from the original |request_url| should be allowed
+  // to be redirected as specified by |redirect_info|.
   bool ShouldRejectRedirect(const GURL& request_url,
-                            int request_load_flags,
                             const net::RedirectInfo& redirect_info);
 
   // Must be called when the |response_head| for a request has been received.
@@ -76,13 +73,6 @@
   void OverrideEntryForTests(const GURL& url,
                              std::unique_ptr<ExtensionThrottleEntry> entry);
 
-  // Sets whether to ignore net::LOAD_MAYBE_USER_GESTURE of the request for
-  // testing. Otherwise, requests will not be throttled when they may have been
-  // throttled in response to a recent user gesture, though they're still
-  // counted for the purpose of throttling other requests.
-  void SetIgnoreUserGestureLoadFlagForTests(
-      bool ignore_user_gesture_load_flag_for_tests);
-
   int GetNumberOfEntriesForTests() const { return url_entries_.size(); }
 
  protected:
@@ -133,8 +123,6 @@
   // Valid after construction.
   GURL::Replacements url_id_replacements_;
 
-  bool ignore_user_gesture_load_flag_for_tests_;
-
   // This is null when it is not set for tests.
   std::unique_ptr<net::BackoffEntry::Policy> backoff_policy_for_tests_;
 
diff --git a/extensions/renderer/extension_throttle_simulation_unittest.cc b/extensions/renderer/extension_throttle_simulation_unittest.cc
index 35d25e3..ea2c489 100644
--- a/extensions/renderer/extension_throttle_simulation_unittest.cc
+++ b/extensions/renderer/extension_throttle_simulation_unittest.cc
@@ -27,7 +27,6 @@
 #include "base/time/time.h"
 #include "extensions/renderer/extension_throttle_entry.h"
 #include "extensions/renderer/extension_throttle_test_support.h"
-#include "net/base/load_flags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::TimeDelta;
@@ -405,7 +404,7 @@
 
     if (throttler_entry_->ImplGetTimeNow() - time_of_last_attempt_ >
         effective_delay) {
-      if (!throttler_entry_->ShouldRejectRequest(net::LOAD_NORMAL)) {
+      if (!throttler_entry_->ShouldRejectRequest()) {
         int status_code = server_->HandleRequest();
         throttler_entry_->UpdateWithResponse(status_code);
 
diff --git a/extensions/renderer/extension_throttle_unittest.cc b/extensions/renderer/extension_throttle_unittest.cc
index 83e56a5e3..a9bbe32 100644
--- a/extensions/renderer/extension_throttle_unittest.cc
+++ b/extensions/renderer/extension_throttle_unittest.cc
@@ -11,7 +11,6 @@
 #include "extensions/renderer/extension_throttle_entry.h"
 #include "extensions/renderer/extension_throttle_manager.h"
 #include "extensions/renderer/extension_throttle_test_support.h"
-#include "net/base/load_flags.h"
 #include "net/url_request/redirect_info.h"
 #include "services/network/public/cpp/resource_response.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -60,10 +59,6 @@
 
   BackoffEntry* GetBackoffEntry() override { return &backoff_entry_; }
 
-  static bool ExplicitUserRequest(int load_flags) {
-    return ExtensionThrottleEntry::ExplicitUserRequest(load_flags);
-  }
-
   void ResetToBlank(const TimeTicks& time_now) {
     fake_clock_.set_now(time_now);
 
@@ -176,25 +171,16 @@
 TEST_F(ExtensionThrottleEntryTest, CanThrottleRequest) {
   entry_->set_exponential_backoff_release_time(entry_->ImplGetTimeNow() +
                                                TimeDelta::FromMilliseconds(1));
-
-  EXPECT_TRUE(entry_->ShouldRejectRequest(net::LOAD_NORMAL));
+  EXPECT_TRUE(entry_->ShouldRejectRequest());
 }
 
-TEST_F(ExtensionThrottleEntryTest, InterfaceDuringExponentialBackoff) {
-  entry_->set_exponential_backoff_release_time(entry_->ImplGetTimeNow() +
-                                               TimeDelta::FromMilliseconds(1));
-  EXPECT_TRUE(entry_->ShouldRejectRequest(net::LOAD_NORMAL));
-
-  // Also end-to-end test the load flags exceptions.
-  EXPECT_FALSE(entry_->ShouldRejectRequest(net::LOAD_MAYBE_USER_GESTURE));
-}
-
-TEST_F(ExtensionThrottleEntryTest, InterfaceNotDuringExponentialBackoff) {
+TEST_F(ExtensionThrottleEntryTest,
+       CanThrottleRequestNotDuringExponentialBackoff) {
   entry_->set_exponential_backoff_release_time(entry_->ImplGetTimeNow());
-  EXPECT_FALSE(entry_->ShouldRejectRequest(net::LOAD_NORMAL));
+  EXPECT_FALSE(entry_->ShouldRejectRequest());
   entry_->set_exponential_backoff_release_time(entry_->ImplGetTimeNow() -
                                                TimeDelta::FromMilliseconds(1));
-  EXPECT_FALSE(entry_->ShouldRejectRequest(net::LOAD_NORMAL));
+  EXPECT_FALSE(entry_->ShouldRejectRequest());
 }
 
 TEST_F(ExtensionThrottleEntryTest, InterfaceUpdateFailure) {
@@ -296,14 +282,6 @@
   EXPECT_EQ(time_4, entry_->sliding_window_release_time());
 }
 
-TEST_F(ExtensionThrottleEntryTest, ExplicitUserRequest) {
-  ASSERT_FALSE(MockExtensionThrottleEntry::ExplicitUserRequest(0));
-  ASSERT_TRUE(MockExtensionThrottleEntry::ExplicitUserRequest(
-      net::LOAD_MAYBE_USER_GESTURE));
-  ASSERT_FALSE(MockExtensionThrottleEntry::ExplicitUserRequest(
-      ~net::LOAD_MAYBE_USER_GESTURE));
-}
-
 TEST(ExtensionThrottleManagerTest, IsUrlStandardised) {
   MockExtensionThrottleManager manager;
   GurlAndString test_values[] = {
@@ -366,11 +344,11 @@
   // A localhost entry should always be opted out.
   ExtensionThrottleEntry* localhost_entry =
       manager.RegisterRequestUrl(GURL("http://localhost/hello"));
-  EXPECT_FALSE(localhost_entry->ShouldRejectRequest(net::LOAD_NORMAL));
+  EXPECT_FALSE(localhost_entry->ShouldRejectRequest());
   for (int i = 0; i < 10; ++i) {
     localhost_entry->UpdateWithResponse(503);
   }
-  EXPECT_FALSE(localhost_entry->ShouldRejectRequest(net::LOAD_NORMAL));
+  EXPECT_FALSE(localhost_entry->ShouldRejectRequest());
 
   // We're not mocking out GetTimeNow() in this scenario
   // so add a 100 ms buffer to avoid flakiness (that should always
@@ -388,7 +366,7 @@
     for (int j = 0; j < 10; ++j) {
       entry_before->UpdateWithResponse(503);
     }
-    EXPECT_TRUE(entry_before->ShouldRejectRequest(net::LOAD_NORMAL));
+    EXPECT_TRUE(entry_before->ShouldRejectRequest());
 
     switch (i) {
       case 0:
@@ -403,20 +381,19 @@
 
     ExtensionThrottleEntry* entry_after =
         manager.RegisterRequestUrl(GURL("http://www.example.com/"));
-    EXPECT_FALSE(entry_after->ShouldRejectRequest(net::LOAD_NORMAL));
+    EXPECT_FALSE(entry_after->ShouldRejectRequest());
   }
 }
 
 TEST(ExtensionThrottleManagerTest, UseAfterNetworkChange) {
   MockExtensionThrottleManager manager;
   const GURL test_url("http://www.example.com/");
-  EXPECT_FALSE(manager.ShouldRejectRequest(test_url, net::LOAD_NORMAL));
+  EXPECT_FALSE(manager.ShouldRejectRequest(test_url));
   manager.SetOnline(/*is_online=*/false);
   manager.SetOnline(/*is_online=*/true);
   net::RedirectInfo redirect_info;
   redirect_info.new_url = GURL("http://www.newsite.com");
-  EXPECT_FALSE(
-      manager.ShouldRejectRedirect(test_url, net::LOAD_NORMAL, redirect_info));
+  EXPECT_FALSE(manager.ShouldRejectRedirect(test_url, redirect_info));
   manager.SetOnline(/*is_online=*/false);
   manager.SetOnline(/*is_online=*/true);
   network::ResourceResponseHead response_head;
diff --git a/extensions/renderer/extension_url_loader_throttle.cc b/extensions/renderer/extension_url_loader_throttle.cc
index aacf431..5059e2c 100644
--- a/extensions/renderer/extension_url_loader_throttle.cc
+++ b/extensions/renderer/extension_url_loader_throttle.cc
@@ -26,8 +26,7 @@
     network::ResourceRequest* request,
     bool* defer) {
   start_request_url_ = request->url;
-  request_load_flags_ = request->load_flags;
-  if (manager_->ShouldRejectRequest(start_request_url_, request_load_flags_))
+  if (manager_->ShouldRejectRequest(start_request_url_))
     delegate_->CancelWithError(net::ERR_TEMPORARILY_THROTTLED, kCancelReason);
 }
 
@@ -37,8 +36,7 @@
     bool* /* defer */,
     std::vector<std::string>* /* to_be_removed_request_headers */,
     net::HttpRequestHeaders* /* modified_request_headers */) {
-  if (manager_->ShouldRejectRedirect(start_request_url_, request_load_flags_,
-                                     *redirect_info)) {
+  if (manager_->ShouldRejectRedirect(start_request_url_, *redirect_info)) {
     delegate_->CancelWithError(net::ERR_TEMPORARILY_THROTTLED, kCancelReason);
   }
 }
diff --git a/extensions/renderer/extension_url_loader_throttle.h b/extensions/renderer/extension_url_loader_throttle.h
index 0d4beb6..c12c836 100644
--- a/extensions/renderer/extension_url_loader_throttle.h
+++ b/extensions/renderer/extension_url_loader_throttle.h
@@ -43,7 +43,6 @@
   void DetachFromCurrentSequence() override;
 
   ExtensionThrottleManager* manager_ = nullptr;
-  int request_load_flags_ = 0;
   GURL start_request_url_;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionURLLoaderThrottle);
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.cc b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.cc
index 82819a8..d1dface 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.cc
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.cc
@@ -99,11 +99,10 @@
       // This should translate into a same document navigation.
       return true;
     }
-    // Make sure we're not eligible to self-delete.
-    DCHECK(!internal_id_.empty());
     // If there is already a MHVFC for this |plugin_element|, destroy it.
     RemoveFrameContainerForReason(old_frame_container,
-                                  UMAType::kRemoveFrameContainerUpdatePlugin);
+                                  UMAType::kRemoveFrameContainerUpdatePlugin,
+                                  true /* retain_manager */);
   }
   RecordInteraction(UMAType::kCreateFrameContainer);
   auto frame_container = std::make_unique<MimeHandlerViewFrameContainer>(
@@ -186,7 +185,7 @@
 void MimeHandlerViewContainerManager::DestroyFrameContainer(
     int32_t element_instance_id) {
   if (auto* frame_container = GetFrameContainer(element_instance_id))
-    RemoveFrameContainer(frame_container);
+    RemoveFrameContainer(frame_container, false /* retain manager */);
 }
 
 void MimeHandlerViewContainerManager::DidLoad(int32_t element_instance_id,
@@ -255,14 +254,16 @@
 
 void MimeHandlerViewContainerManager::RemoveFrameContainerForReason(
     MimeHandlerViewFrameContainer* frame_container,
-    MimeHandlerViewUMATypes::Type event) {
-  if (!RemoveFrameContainer(frame_container))
+    MimeHandlerViewUMATypes::Type event,
+    bool retain_manager) {
+  if (!RemoveFrameContainer(frame_container, retain_manager))
     return;
   RecordInteraction(event);
 }
 
 bool MimeHandlerViewContainerManager::RemoveFrameContainer(
-    MimeHandlerViewFrameContainer* frame_container) {
+    MimeHandlerViewFrameContainer* frame_container,
+    bool retain_manager) {
   auto it = std::find_if(frame_containers_.cbegin(), frame_containers_.cend(),
                          [&frame_container](const auto& iter) {
                            return iter.get() == frame_container;
@@ -271,7 +272,7 @@
     return false;
   frame_containers_.erase(it);
 
-  if (!frame_containers_.size() && internal_id_.empty()) {
+  if (!frame_containers_.size() && internal_id_.empty() && !retain_manager) {
     // There are no frame containers left, and we're not serving a full-page
     // MimeHandlerView, so we remove ourselves from the map.
     auto& map = *GetRenderFrameMap();
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.h b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.h
index 095be86..40ea7aa4 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.h
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.h
@@ -81,10 +81,11 @@
   // Removes the |frame_container| from |frame_containers_| and destroys it. The
   // |reason| is emitted for UMA.
   // Note: Calling this function may delete |this| if we are removing the last
-  // frame container.
+  // frame container, unless |retain_manager| is set to true.
   void RemoveFrameContainerForReason(
       MimeHandlerViewFrameContainer* frame_container,
-      MimeHandlerViewUMATypes::Type reason);
+      MimeHandlerViewUMATypes::Type reason,
+      bool retain_manager);
   MimeHandlerViewFrameContainer* GetFrameContainer(
       const blink::WebElement& plugin_element);
   MimeHandlerViewFrameContainer* GetFrameContainer(int32_t element_instance_id);
@@ -117,8 +118,9 @@
   bool IsResourceAccessibleBySource() const override;
 
   // Note: Calling this function may delete |this| if we are removing the last
-  // frame container.
-  bool RemoveFrameContainer(MimeHandlerViewFrameContainer* frame_container);
+  // frame container, unless |retain_manager| is set to true.
+  bool RemoveFrameContainer(MimeHandlerViewFrameContainer* frame_container,
+                            bool retain_manager);
   // mime_handler::BeforeUnloadControl implementation.
   void SetShowBeforeUnloadDialog(
       bool show_dialog,
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_frame_container.cc b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_frame_container.cc
index 1417fb9..2731cd5 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_frame_container.cc
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_frame_container.cc
@@ -59,7 +59,8 @@
 bool MimeHandlerViewFrameContainer::AreFramesAlive() {
   if (!GetContentFrame() || !GetContentFrame()->FirstChild()) {
     container_manager_->RemoveFrameContainerForReason(
-        this, UMATypes::kRemoveFrameContainerUnexpectedFrames);
+        this, UMATypes::kRemoveFrameContainerUnexpectedFrames,
+        false /* retain_manager */);
     return false;
   }
   return true;
@@ -85,7 +86,8 @@
     }
   }
   container_manager_->RemoveFrameContainerForReason(
-      this, UMATypes::kRemoveFrameContainerUnexpectedFrames);
+      this, UMATypes::kRemoveFrameContainerUnexpectedFrames,
+      false /* retain_manager */);
   return false;
 }
 
diff --git a/fuchsia/engine/BUILD.gn b/fuchsia/engine/BUILD.gn
index e2f1395..4a8b066 100644
--- a/fuchsia/engine/BUILD.gn
+++ b/fuchsia/engine/BUILD.gn
@@ -269,6 +269,7 @@
     "browser/cookie_manager_impl_unittest.cc",
     "browser/frame_impl_unittest.cc",
     "browser/url_request_rewrite_rules_manager_unittest.cc",
+    "common/web_engine_url_loader_throttle_unittest.cc",
     "context_provider_impl_unittest.cc",
     "fake_context.cc",
     "fake_context.h",
diff --git a/fuchsia/engine/common/web_engine_url_loader_throttle.cc b/fuchsia/engine/common/web_engine_url_loader_throttle.cc
index 151ca415..14ff2d7 100644
--- a/fuchsia/engine/common/web_engine_url_loader_throttle.cc
+++ b/fuchsia/engine/common/web_engine_url_loader_throttle.cc
@@ -91,17 +91,35 @@
   }
 }
 
+bool HostMatches(const base::StringPiece& url_host,
+                 const base::StringPiece& rule_host) {
+  const base::StringPiece kWildcard("*.");
+  if (base::StartsWith(rule_host, kWildcard, base::CompareCase::SENSITIVE)) {
+    // |rule_host| starts with a wildcard (e.g. "*.test.xyz"). Check if
+    // |url_host| ends with ".test.xyz". The "." character is included here to
+    // prevent accidentally matching "notatest.xyz".
+    if (base::EndsWith(url_host, rule_host.substr(1),
+                       base::CompareCase::SENSITIVE)) {
+      return true;
+    }
+
+    // Check |url_host| is exactly |rule_host| without the wildcard. i.e. if
+    // |rule_host| is "*.test.xyz", check |url_host| is exactly "test.xyz".
+    return base::CompareCaseInsensitiveASCII(url_host, rule_host.substr(2)) ==
+           0;
+  }
+  return base::CompareCaseInsensitiveASCII(url_host, rule_host) == 0;
+}
+
 void ApplyRule(network::ResourceRequest* request,
                const mojom::UrlRequestRewriteRulePtr& rule) {
   const GURL& url = request->url;
 
   if (rule->hosts_filter) {
     bool found = false;
-    for (const auto& host : rule->hosts_filter.value()) {
-      if (url.host().compare(host) == 0) {
-        found = true;
+    for (const base::StringPiece host : rule->hosts_filter.value()) {
+      if ((found = HostMatches(url.host(), host)))
         break;
-      }
     }
     if (!found)
       return;
diff --git a/fuchsia/engine/common/web_engine_url_loader_throttle.h b/fuchsia/engine/common/web_engine_url_loader_throttle.h
index f9ffdcf3..7ed6c85 100644
--- a/fuchsia/engine/common/web_engine_url_loader_throttle.h
+++ b/fuchsia/engine/common/web_engine_url_loader_throttle.h
@@ -9,11 +9,13 @@
 
 #include "base/memory/ref_counted.h"
 #include "fuchsia/engine/url_request_rewrite.mojom.h"
+#include "fuchsia/engine/web_engine_export.h"
 #include "third_party/blink/public/common/loader/url_loader_throttle.h"
 
 // Implements a URLLoaderThrottle for the WebEngine. Applies network request
 // rewrites provided through the fuchsia.web.SetUrlRequestRewriteRules FIDL API.
-class WebEngineURLLoaderThrottle : public blink::URLLoaderThrottle {
+class WEB_ENGINE_EXPORT WebEngineURLLoaderThrottle
+    : public blink::URLLoaderThrottle {
  public:
   using UrlRequestRewriteRules =
       base::RefCountedData<std::vector<mojom::UrlRequestRewriteRulePtr>>;
@@ -33,13 +35,13 @@
       CachedRulesProvider* cached_rules_provider);
   ~WebEngineURLLoaderThrottle() override;
 
- private:
   // blink::URLLoaderThrottle implementation.
   void DetachFromCurrentSequence() override;
   void WillStartRequest(network::ResourceRequest* request,
                         bool* defer) override;
   bool makes_unsafe_redirect() override;
 
+ private:
   CachedRulesProvider* const cached_rules_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(WebEngineURLLoaderThrottle);
diff --git a/fuchsia/engine/common/web_engine_url_loader_throttle_unittest.cc b/fuchsia/engine/common/web_engine_url_loader_throttle_unittest.cc
new file mode 100644
index 0000000..93e370b
--- /dev/null
+++ b/fuchsia/engine/common/web_engine_url_loader_throttle_unittest.cc
@@ -0,0 +1,92 @@
+// 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 "fuchsia/engine/common/web_engine_url_loader_throttle.h"
+
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class TestCachedRulesProvider
+    : public WebEngineURLLoaderThrottle::CachedRulesProvider {
+ public:
+  TestCachedRulesProvider() = default;
+  ~TestCachedRulesProvider() override = default;
+
+  void SetCachedRules(
+      scoped_refptr<WebEngineURLLoaderThrottle::UrlRequestRewriteRules>
+          cached_rules) {
+    cached_rules_ = cached_rules;
+  }
+
+  // WebEngineURLLoaderThrottle::CachedRulesProvider implementation.
+  scoped_refptr<WebEngineURLLoaderThrottle::UrlRequestRewriteRules>
+  GetCachedRules() override {
+    return cached_rules_;
+  }
+
+ private:
+  scoped_refptr<WebEngineURLLoaderThrottle::UrlRequestRewriteRules>
+      cached_rules_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestCachedRulesProvider);
+};
+
+}  // namespace
+
+class WebEngineURLLoaderThrottleTest : public testing::Test {
+ public:
+  WebEngineURLLoaderThrottleTest()
+      : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
+  ~WebEngineURLLoaderThrottleTest() override = default;
+
+ protected:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+};
+
+// Tests rules are properly applied when wildcard-filtering is used on hosts.
+TEST_F(WebEngineURLLoaderThrottleTest, WildcardHosts) {
+  mojom::UrlRequestRewriteAddHeadersPtr add_headers =
+      mojom::UrlRequestRewriteAddHeaders::New();
+  add_headers->headers.SetHeader("Header", "Value");
+  mojom::UrlRequestRewritePtr rewrite =
+      mojom::UrlRequestRewrite::NewAddHeaders(std::move(add_headers));
+  std::vector<mojom::UrlRequestRewritePtr> rewrites;
+  rewrites.push_back(std::move(rewrite));
+  mojom::UrlRequestRewriteRulePtr rule = mojom::UrlRequestRewriteRule::New();
+  rule->hosts_filter = base::Optional<std::vector<std::string>>({"*.test.net"});
+  rule->rewrites = std::move(rewrites);
+
+  std::vector<mojom::UrlRequestRewriteRulePtr> rules;
+  rules.push_back(std::move(rule));
+
+  TestCachedRulesProvider provider;
+  provider.SetCachedRules(
+      base::MakeRefCounted<WebEngineURLLoaderThrottle::UrlRequestRewriteRules>(
+          std::move(rules)));
+
+  WebEngineURLLoaderThrottle throttle(&provider);
+  bool defer = false;
+
+  network::ResourceRequest request1;
+  request1.url = GURL("http://test.net");
+  throttle.WillStartRequest(&request1, &defer);
+  EXPECT_TRUE(request1.headers.HasHeader("Header"));
+
+  network::ResourceRequest request2;
+  request2.url = GURL("http://subdomain.test.net");
+  throttle.WillStartRequest(&request2, &defer);
+  EXPECT_TRUE(request2.headers.HasHeader("Header"));
+
+  network::ResourceRequest request3;
+  request3.url = GURL("http://domaintest.net");
+  throttle.WillStartRequest(&request3, &defer);
+  EXPECT_FALSE(request3.headers.HasHeader("Header"));
+
+  network::ResourceRequest request4;
+  request4.url = GURL("http://otherdomain.net");
+  throttle.WillStartRequest(&request4, &defer);
+  EXPECT_FALSE(request4.headers.HasHeader("Header"));
+}
diff --git a/gpu/command_buffer/client/context_support.h b/gpu/command_buffer/client/context_support.h
index f6b7ab2..99b1fd7 100644
--- a/gpu/command_buffer/client/context_support.h
+++ b/gpu/command_buffer/client/context_support.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/containers/span.h"
 #include "ui/gfx/overlay_transform.h"
 #include "ui/gfx/presentation_feedback.h"
 
@@ -21,6 +20,10 @@
 class RectF;
 }
 
+namespace cc {
+struct ImageHeaderMetadata;
+}
+
 namespace gpu {
 
 struct SwapBuffersCompleteParams;
@@ -141,11 +144,12 @@
   // Determines if hardware decode acceleration is supported for WebP images.
   virtual bool IsWebPDecodeAccelerationSupported() const = 0;
 
-  // Determines if an encoded image can be decoded using hardware decode
-  // acceleration. If this method returns true, then the client can be confident
-  // that a call to RasterInterface::ScheduleImageDecode() will succeed.
+  // Determines if |image_metadata| corresponds to an image that can be decoded
+  // using hardware decode acceleration. If this method returns true, then the
+  // client can be confident that a call to
+  // RasterInterface::ScheduleImageDecode() will succeed.
   virtual bool CanDecodeWithHardwareAcceleration(
-      base::span<const uint8_t> encoded_data) const = 0;
+      const cc::ImageHeaderMetadata* image_metadata) const = 0;
 
   // Returns true if the context provider automatically manages calls to
   // GrContext::resetContext under the hood to prevent GL state synchronization
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index faf6905..914d6f12 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -6788,7 +6788,7 @@
 }
 
 bool GLES2Implementation::CanDecodeWithHardwareAcceleration(
-    base::span<const uint8_t> encoded_data) const {
+    const cc::ImageHeaderMetadata* image_metadata) const {
   NOTREACHED();
   return false;
 }
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 1b841f2..9f3d8b2b 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -147,7 +147,7 @@
   bool IsJpegDecodeAccelerationSupported() const override;
   bool IsWebPDecodeAccelerationSupported() const override;
   bool CanDecodeWithHardwareAcceleration(
-      base::span<const uint8_t> encoded_data) const override;
+      const cc::ImageHeaderMetadata* image_metadata) const override;
 
   // InterfaceBase implementation.
   void GenSyncTokenCHROMIUM(GLbyte* sync_token) override;
diff --git a/gpu/command_buffer/client/image_decode_accelerator_interface.h b/gpu/command_buffer/client/image_decode_accelerator_interface.h
index 1a94e0e..7ec8817 100644
--- a/gpu/command_buffer/client/image_decode_accelerator_interface.h
+++ b/gpu/command_buffer/client/image_decode_accelerator_interface.h
@@ -11,6 +11,10 @@
 #include "gpu/command_buffer/common/command_buffer_id.h"
 #include "gpu/command_buffer/common/sync_token.h"
 
+namespace cc {
+struct ImageHeaderMetadata;
+}
+
 namespace gfx {
 class ColorSpace;
 class Size;
@@ -25,7 +29,7 @@
   virtual ~ImageDecodeAcceleratorInterface() {}
 
   virtual bool IsImageSupported(
-      base::span<const uint8_t> encoded_data) const = 0;
+      const cc::ImageHeaderMetadata* image_metadata) const = 0;
 
   virtual bool IsJpegDecodeAccelerationSupported() const = 0;
 
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc
index 3540d07..93da3f45 100644
--- a/gpu/command_buffer/client/raster_implementation.cc
+++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -554,9 +554,9 @@
 }
 
 bool RasterImplementation::CanDecodeWithHardwareAcceleration(
-    base::span<const uint8_t> encoded_data) const {
+    const cc::ImageHeaderMetadata* image_metadata) const {
   return image_decode_accelerator_ &&
-         image_decode_accelerator_->IsImageSupported(encoded_data);
+         image_decode_accelerator_->IsImageSupported(image_metadata);
 }
 
 const std::string& RasterImplementation::GetLogPrefix() const {
diff --git a/gpu/command_buffer/client/raster_implementation.h b/gpu/command_buffer/client/raster_implementation.h
index 0825a9a..f8beb58 100644
--- a/gpu/command_buffer/client/raster_implementation.h
+++ b/gpu/command_buffer/client/raster_implementation.h
@@ -186,7 +186,7 @@
   bool IsJpegDecodeAccelerationSupported() const override;
   bool IsWebPDecodeAccelerationSupported() const override;
   bool CanDecodeWithHardwareAcceleration(
-      base::span<const uint8_t> encoded_data) const override;
+      const cc::ImageHeaderMetadata* image_metadata) const override;
 
   // InterfaceBase implementation.
   void GenSyncTokenCHROMIUM(GLbyte* sync_token) override;
diff --git a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
index f191b0a..d50e428 100644
--- a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
+++ b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
@@ -229,7 +229,7 @@
   bool IsJpegDecodeAccelerationSupported() const override { return false; }
   bool IsWebPDecodeAccelerationSupported() const override { return false; }
   bool CanDecodeWithHardwareAcceleration(
-      base::span<const uint8_t> encoded_data) const override {
+      const cc::ImageHeaderMetadata* image_metadata) const override {
     return false;
   }
   bool HasGrContextSupport() const override { return false; }
diff --git a/gpu/command_buffer/client/webgpu_implementation.cc b/gpu/command_buffer/client/webgpu_implementation.cc
index 1fe00d3..4093874 100644
--- a/gpu/command_buffer/client/webgpu_implementation.cc
+++ b/gpu/command_buffer/client/webgpu_implementation.cc
@@ -173,7 +173,7 @@
   return false;
 }
 bool WebGPUImplementation::CanDecodeWithHardwareAcceleration(
-    base::span<const uint8_t> encoded_data) const {
+    const cc::ImageHeaderMetadata* image_metadata) const {
   NOTREACHED();
   return false;
 }
diff --git a/gpu/command_buffer/client/webgpu_implementation.h b/gpu/command_buffer/client/webgpu_implementation.h
index 4c56924..982a1c3b 100644
--- a/gpu/command_buffer/client/webgpu_implementation.h
+++ b/gpu/command_buffer/client/webgpu_implementation.h
@@ -86,7 +86,7 @@
   bool IsJpegDecodeAccelerationSupported() const override;
   bool IsWebPDecodeAccelerationSupported() const override;
   bool CanDecodeWithHardwareAcceleration(
-      base::span<const uint8_t> encoded_data) const override;
+      const cc::ImageHeaderMetadata* image_metadata) const override;
 
   // InterfaceBase implementation.
   void GenSyncTokenCHROMIUM(GLbyte* sync_token) override;
diff --git a/gpu/ipc/client/BUILD.gn b/gpu/ipc/client/BUILD.gn
index ad92416..a0ce893 100644
--- a/gpu/ipc/client/BUILD.gn
+++ b/gpu/ipc/client/BUILD.gn
@@ -33,11 +33,11 @@
   ]
   deps = [
     "//base",
+    "//cc/paint",
     "//gpu/command_buffer/client:client_sources",
     "//gpu/command_buffer/common:common_sources",
     "//gpu/config:config_sources",
     "//gpu/ipc/common:ipc_common_sources",
-    "//media/parsers",
     "//mojo/public/cpp/system",
     "//ui/gfx:color_space",
     "//ui/gfx/geometry",
diff --git a/gpu/ipc/client/DEPS b/gpu/ipc/client/DEPS
index b6aef8d..5a3dccc 100644
--- a/gpu/ipc/client/DEPS
+++ b/gpu/ipc/client/DEPS
@@ -11,9 +11,7 @@
     "+components/viz/test/test_gpu_memory_buffer_manager.h",
   ],
   "image_decode_accelerator_proxy.cc": [
-    "+media/parsers/jpeg_parser.h",
-    "+media/parsers/vp8_parser.h",
-    "+media/parsers/webp_parser.h",
+    "+cc/paint/paint_image.h",
   ],
   "raster_in_process_context_tests.cc": [
     "+components/viz/common/resources/resource_format.h",
diff --git a/gpu/ipc/client/image_decode_accelerator_proxy.cc b/gpu/ipc/client/image_decode_accelerator_proxy.cc
index cfb5143..76029007 100644
--- a/gpu/ipc/client/image_decode_accelerator_proxy.cc
+++ b/gpu/ipc/client/image_decode_accelerator_proxy.cc
@@ -4,23 +4,18 @@
 
 #include "gpu/ipc/client/image_decode_accelerator_proxy.h"
 
-#include <string.h>
-
 #include <algorithm>
 #include <memory>
 #include <utility>
 #include <vector>
 
 #include "base/logging.h"
-#include "base/numerics/safe_conversions.h"
+#include "cc/paint/paint_image.h"
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "gpu/ipc/common/command_buffer_id.h"
 #include "gpu/ipc/common/gpu_messages.h"
-#include "media/parsers/jpeg_parser.h"
-#include "media/parsers/vp8_parser.h"
-#include "media/parsers/webp_parser.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -28,126 +23,67 @@
 
 namespace {
 
-bool IsJpegImage(base::span<const uint8_t> encoded_data) {
-  if (encoded_data.size() < 3u)
-    return false;
-  return memcmp("\xFF\xD8\xFF", encoded_data.data(), 3u) == 0;
-}
+// TODO(crbug.com/984971): for WebPs we may need to compute the coded size
+// instead and check that against the supported dimensions.
+bool IsSupportedImageSize(
+    const cc::ImageHeaderMetadata* image_data,
+    const ImageDecodeAcceleratorSupportedProfile& supported_profile) {
+  DCHECK(image_data);
 
-ImageDecodeAcceleratorType GetImageType(
-    base::span<const uint8_t> encoded_data) {
-  static_assert(static_cast<int>(ImageDecodeAcceleratorType::kMaxValue) == 2,
-                "GetImageType() must be adapted to support all image types in "
-                "ImageDecodeAcceleratorType");
+  gfx::Size image_size;
+  if (image_data->coded_size.has_value())
+    image_size = image_data->coded_size.value();
+  else
+    image_size = image_data->image_size;
 
-  if (IsJpegImage(encoded_data))
-    return ImageDecodeAcceleratorType::kJpeg;
-
-  if (media::IsLossyWebPImage(encoded_data))
-    return ImageDecodeAcceleratorType::kWebP;
-
-  return ImageDecodeAcceleratorType::kUnknown;
-}
-
-bool GetJpegSubsampling(const media::JpegParseResult& parse_result,
-                        ImageDecodeAcceleratorSubsampling* subsampling) {
-  static_assert(
-      static_cast<int>(ImageDecodeAcceleratorSubsampling::kMaxValue) == 2,
-      "GetJpegSubsampling() must be adapted to support all "
-      "subsampling factors in ImageDecodeAcceleratorSubsampling");
-
-  // Currently, only 3 components are supported (this excludes, for example,
-  // grayscale and CMYK JPEGs).
-  if (parse_result.frame_header.num_components != 3u)
-    return false;
-
-  const uint8_t comp0_h =
-      parse_result.frame_header.components[0].horizontal_sampling_factor;
-  const uint8_t comp0_v =
-      parse_result.frame_header.components[0].vertical_sampling_factor;
-  const uint8_t comp1_h =
-      parse_result.frame_header.components[1].horizontal_sampling_factor;
-  const uint8_t comp1_v =
-      parse_result.frame_header.components[1].vertical_sampling_factor;
-  const uint8_t comp2_h =
-      parse_result.frame_header.components[2].horizontal_sampling_factor;
-  const uint8_t comp2_v =
-      parse_result.frame_header.components[2].vertical_sampling_factor;
-
-  if (comp1_h != 1u || comp1_v != 1u || comp2_h != 1u || comp2_v != 1u)
-    return false;
-
-  if (comp0_h == 2u && comp0_v == 2u) {
-    *subsampling = ImageDecodeAcceleratorSubsampling::k420;
-    return true;
-  } else if (comp0_h == 2u && comp0_v == 1u) {
-    *subsampling = ImageDecodeAcceleratorSubsampling::k422;
-    return true;
-  } else if (comp0_h == 1u && comp0_v == 1u) {
-    *subsampling = ImageDecodeAcceleratorSubsampling::k444;
-    return true;
-  }
-  return false;
+  return image_size.width() >=
+             supported_profile.min_encoded_dimensions.width() &&
+         image_size.height() >=
+             supported_profile.min_encoded_dimensions.height() &&
+         image_size.width() <=
+             supported_profile.max_encoded_dimensions.width() &&
+         image_size.height() <=
+             supported_profile.max_encoded_dimensions.height();
 }
 
 bool IsSupportedJpegImage(
-    base::span<const uint8_t> encoded_data,
+    const cc::ImageHeaderMetadata* image_data,
     const ImageDecodeAcceleratorSupportedProfile& supported_profile) {
-  DCHECK(IsJpegImage(encoded_data));
+  DCHECK(image_data);
+  DCHECK_EQ(cc::ImageType::kJPEG, image_data->image_type);
   DCHECK_EQ(ImageDecodeAcceleratorType::kJpeg, supported_profile.image_type);
 
-  // First, parse the JPEG file. This fails for progressive JPEGs (which we
-  // don't support anyway).
-  media::JpegParseResult parse_result;
-  if (!media::ParseJpegPicture(encoded_data.data(), encoded_data.size(),
-                               &parse_result)) {
+  DCHECK(image_data->jpeg_is_progressive.has_value());
+  if (image_data->jpeg_is_progressive.value())
     return false;
-  }
 
-  // Now, check the chroma subsampling format.
+  // Check the chroma subsampling format.
+  static_assert(
+      // TODO(andrescj): refactor to instead have a static_assert at the
+      // declaration site of ImageDecodeAcceleratorSubsampling to make sure it
+      // has the same number of entries as cc::YUVSubsampling.
+      static_cast<int>(ImageDecodeAcceleratorSubsampling::kMaxValue) == 2,
+      "IsSupportedJpegImage() must be adapted to support all subsampling "
+      "factors in ImageDecodeAcceleratorSubsampling");
   ImageDecodeAcceleratorSubsampling subsampling;
-  if (!GetJpegSubsampling(parse_result, &subsampling))
-    return false;
-  if (std::find(supported_profile.subsamplings.cbegin(),
-                supported_profile.subsamplings.cend(),
-                subsampling) == supported_profile.subsamplings.cend()) {
-    return false;
+  switch (image_data->yuv_subsampling) {
+    case cc::YUVSubsampling::k420:
+      subsampling = ImageDecodeAcceleratorSubsampling::k420;
+      break;
+    case cc::YUVSubsampling::k422:
+      subsampling = ImageDecodeAcceleratorSubsampling::k422;
+      break;
+    case cc::YUVSubsampling::k444:
+      subsampling = ImageDecodeAcceleratorSubsampling::k444;
+      break;
+    default:
+      // Currently not supporting any other subsampling format.
+      return false;
   }
 
-  // Now, check the dimensions.
-  const int encoded_width =
-      base::strict_cast<int>(parse_result.frame_header.coded_width);
-  const int encoded_height =
-      base::strict_cast<int>(parse_result.frame_header.coded_height);
-  if (encoded_width < supported_profile.min_encoded_dimensions.width() ||
-      encoded_height < supported_profile.min_encoded_dimensions.height() ||
-      encoded_width > supported_profile.max_encoded_dimensions.width() ||
-      encoded_height > supported_profile.max_encoded_dimensions.height()) {
-    return false;
-  }
-
-  return true;
-}
-
-bool IsSupportedWebPImage(
-    base::span<const uint8_t> encoded_data,
-    const ImageDecodeAcceleratorSupportedProfile& supported_profile) {
-  DCHECK(media::IsLossyWebPImage(encoded_data));
-  DCHECK_EQ(ImageDecodeAcceleratorType::kWebP, supported_profile.image_type);
-
-  const std::unique_ptr<media::Vp8FrameHeader> parse_result =
-      media::ParseWebPImage(encoded_data);
-  if (!parse_result)
-    return false;
-
-  // TODO(crbug.com/984971): we may need to compute the coded size instead and
-  // check that against the supported dimensions.
-  const int width = base::strict_cast<int>(parse_result->width);
-  const int height = base::strict_cast<int>(parse_result->height);
-  return width >= supported_profile.min_encoded_dimensions.width() &&
-         height >= supported_profile.min_encoded_dimensions.height() &&
-         width <= supported_profile.max_encoded_dimensions.width() &&
-         height <= supported_profile.max_encoded_dimensions.height();
+  return std::find(supported_profile.subsamplings.cbegin(),
+                   supported_profile.subsamplings.cend(),
+                   subsampling) != supported_profile.subsamplings.cend();
 }
 
 }  // namespace
@@ -159,13 +95,39 @@
 ImageDecodeAcceleratorProxy::~ImageDecodeAcceleratorProxy() {}
 
 bool ImageDecodeAcceleratorProxy::IsImageSupported(
-    base::span<const uint8_t> encoded_data) const {
+    const cc::ImageHeaderMetadata* image_metadata) const {
   DCHECK(host_);
 
-  const ImageDecodeAcceleratorType image_type = GetImageType(encoded_data);
-  if (image_type == ImageDecodeAcceleratorType::kUnknown)
+  if (!image_metadata)
     return false;
 
+  // Image is supported only if all the encoded data was received prior to any
+  // decoding work. Otherwise, it means that the software decoder has already
+  // started decoding the image, so we just let it finish.
+  if (!image_metadata->all_data_received_prior_to_decode)
+    return false;
+
+  // Image is supported only if the image doesn't have an embedded color space.
+  // This is because we don't currently send the embedded color profile with the
+  // decode request.
+  if (image_metadata->has_embedded_color_profile)
+    return false;
+
+  static_assert(static_cast<int>(ImageDecodeAcceleratorType::kMaxValue) == 2,
+                "IsImageSupported() must be adapted to support all image types "
+                "in ImageDecodeAcceleratorType");
+  ImageDecodeAcceleratorType image_type = ImageDecodeAcceleratorType::kUnknown;
+  switch (image_metadata->image_type) {
+    case cc::ImageType::kJPEG:
+      image_type = ImageDecodeAcceleratorType::kJpeg;
+      break;
+    case cc::ImageType::kWEBP:
+      image_type = ImageDecodeAcceleratorType::kWebP;
+      break;
+    default:
+      return false;
+  }
+
   // Find the image decode accelerator supported profile according to the type
   // of the image.
   const std::vector<ImageDecodeAcceleratorSupportedProfile>& profiles =
@@ -178,14 +140,20 @@
   if (profile_it == profiles.cend())
     return false;
 
+  // Verify that the image size is supported.
+  if (!IsSupportedImageSize(image_metadata, *profile_it))
+    return false;
+
   // Validate the image according to that profile.
   switch (image_type) {
     case ImageDecodeAcceleratorType::kJpeg:
-      return IsSupportedJpegImage(encoded_data, *profile_it);
+      return IsSupportedJpegImage(image_metadata, *profile_it);
     case ImageDecodeAcceleratorType::kWebP:
-      return IsSupportedWebPImage(encoded_data, *profile_it);
+      DCHECK(image_metadata->webp_is_non_extended_lossy.has_value());
+      return image_metadata->webp_is_non_extended_lossy.value();
     case ImageDecodeAcceleratorType::kUnknown:
-      // No Op. Should not reach due to a check above.
+      // Should not reach due to a check above.
+      NOTREACHED();
       break;
   }
   return false;
@@ -224,7 +192,6 @@
   DCHECK(host_);
   DCHECK_EQ(host_->channel_id(),
             ChannelIdFromCommandBufferId(raster_decoder_command_buffer_id));
-  DCHECK(IsImageSupported(encoded_data));
 
   GpuChannelMsg_ScheduleImageDecode_Params params;
   params.encoded_data =
diff --git a/gpu/ipc/client/image_decode_accelerator_proxy.h b/gpu/ipc/client/image_decode_accelerator_proxy.h
index 38d021e..a47df5d 100644
--- a/gpu/ipc/client/image_decode_accelerator_proxy.h
+++ b/gpu/ipc/client/image_decode_accelerator_proxy.h
@@ -50,11 +50,12 @@
   ImageDecodeAcceleratorProxy(GpuChannelHost* host, int32_t route_id);
   ~ImageDecodeAcceleratorProxy() override;
 
-  // Determines if an encoded image is supported by the hardware accelerator.
-  // The ScheduleImageDecode() method should only be called for images for which
-  // IsImageSupported() returns true. Otherwise, the client faces a GPU channel
-  // teardown if the decode fails.
-  bool IsImageSupported(base::span<const uint8_t> encoded_data) const override;
+  // Determines if |image_metadata| corresponds to an image that can be decoded
+  // using hardware decode acceleration. The ScheduleImageDecode() method should
+  // only be called for images for which IsImageSupported() returns true.
+  // Otherwise, the client faces a GPU channel teardown if the decode fails.
+  bool IsImageSupported(
+      const cc::ImageHeaderMetadata* image_metadata) const override;
 
   // Determines if hardware decode acceleration is supported for JPEG images.
   bool IsJpegDecodeAccelerationSupported() const override;
diff --git a/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h b/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h
index 297a159..907b55c 100644
--- a/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h
+++ b/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h
@@ -14,7 +14,7 @@
 #include <memory>
 
 #include "base/bind.h"
-#include "base/task/single_thread_task_executor.h"
+#include "base/test/task_environment.h"
 #include "build/build_config.h"
 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
 #include "mojo/public/cpp/base/shared_memory_mojom_traits.h"
@@ -23,7 +23,7 @@
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/mojom/buffer_types_mojom_traits.h"
 
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(USE_OZONE)
 #include "ui/gl/init/gl_factory.h"
 #include "ui/gl/test/gl_surface_test_support.h"
 #endif
@@ -50,12 +50,16 @@
     return &gpu_memory_buffer_support_;
   }
 
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(USE_OZONE)
   // Overridden from testing::Test:
   void SetUp() override { gl::GLSurfaceTestSupport::InitializeOneOff(); }
   void TearDown() override { gl::init::ShutdownGL(false); }
 #endif
 
+ protected:
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::MainThreadType::UI};
+
  private:
   GpuMemoryBufferSupport gpu_memory_buffer_support_;
 
@@ -297,7 +301,6 @@
 }
 
 TYPED_TEST_P(GpuMemoryBufferImplTest, SerializeAndDeserialize) {
-  base::SingleThreadTaskExecutor main_task_executor;
   const gfx::Size kBufferSize(8, 8);
   const gfx::GpuMemoryBufferType kBufferType = TypeParam::kBufferType;
 
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn
index 96851a363..082ac93 100644
--- a/gpu/ipc/service/BUILD.gn
+++ b/gpu/ipc/service/BUILD.gn
@@ -150,6 +150,7 @@
     "//testing/gtest:gtest",
   ]
   deps = [
+    "//base/test:test_support",
     "//gpu/ipc/common",
     "//ui/gl:test_support",
   ]
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h b/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h
index 34227ac..900fd2a6 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h
@@ -8,14 +8,15 @@
 #ifndef GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_TEST_TEMPLATE_H_
 #define GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_TEST_TEMPLATE_H_
 
+#include "base/test/task_environment.h"
+#include "build/build_config.h"
 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
 #include "gpu/ipc/service/gpu_memory_buffer_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/buffer_format_util.h"
 
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(USE_OZONE)
 #include "base/command_line.h"
-#include "build/build_config.h"
 #include "ui/gl/gl_switches.h"
 #include "ui/gl/init/gl_factory.h"
 #include "ui/gl/test/gl_surface_test_support.h"
@@ -26,18 +27,23 @@
 template <typename GpuMemoryBufferFactoryType>
 class GpuMemoryBufferFactoryTest : public testing::Test {
  public:
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(USE_OZONE)
   // Overridden from testing::Test:
   void SetUp() override {
+#if defined(OS_WIN)
     // This test only works with hardware rendering.
     DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
         switches::kUseGpuInTests));
+#endif
     gl::GLSurfaceTestSupport::InitializeOneOff();
   }
   void TearDown() override { gl::init::ShutdownGL(false); }
-#endif
+#endif  // defined(OS_WIN) || defined(USE_OZONE)
 
  protected:
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::MainThreadType::UI};
+
   GpuMemoryBufferFactoryType factory_;
 };
 
diff --git a/ios/build/bots/scripts/test_runner.py b/ios/build/bots/scripts/test_runner.py
index b444ff924..01dc61f 100644
--- a/ios/build/bots/scripts/test_runner.py
+++ b/ios/build/bots/scripts/test_runner.py
@@ -1083,6 +1083,12 @@
     for test_arg in self.test_args:
       cmd.extend(['-c', test_arg])
 
+      # If --run-with-custom-webkit is passed as a test arg, set
+      # DYLD_FRAMEWORK_PATH to point to the embedded custom webkit frameworks.
+      if test_arg == '--run-with-custom-webkit':
+        cmd.extend(['-e', 'DYLD_FRAMEWORK_PATH=' +
+                    os.path.join(self.app_path, 'WebKitFrameworks')])
+
     if self.xctest_path:
       self.sharding_cmd = cmd[:]
       if test_filter:
diff --git a/ios/build/bots/scripts/xcodebuild_runner.py b/ios/build/bots/scripts/xcodebuild_runner.py
index 4d075fe..e0a0d14 100644
--- a/ios/build/bots/scripts/xcodebuild_runner.py
+++ b/ios/build/bots/scripts/xcodebuild_runner.py
@@ -175,6 +175,17 @@
       A node with filled required fields about egtests.
     """
     module = self.module_name + '_module'
+
+    # If --run-with-custom-webkit is passed as a test arg, set up
+    # DYLD_FRAMEWORK_PATH to load the custom webkit modules.
+    dyld_framework_path = self.project_path + ':'
+    if '--run-with-custom-webkit' in self.test_args:
+      if self.host_app_path:
+        webkit_path = os.path.join(self.host_app_path, 'WebKitFrameworks')
+      else:
+        webkit_path = os.path.join(self.egtests_path, 'WebKitFrameworks')
+      dyld_framework_path = dyld_framework_path + webkit_path + ':'
+
     module_data = {
         'TestBundlePath': '__TESTHOST__%s' % self._xctest_path(),
         'TestHostPath': '%s' % self.egtests_path,
@@ -183,7 +194,7 @@
                 '__PLATFORMS__/iPhoneSimulator.platform/Developer/'
                 'usr/lib/libXCTestBundleInject.dylib'),
             'DYLD_LIBRARY_PATH': self.project_path,
-            'DYLD_FRAMEWORK_PATH': self.project_path + ':',
+            'DYLD_FRAMEWORK_PATH': dyld_framework_path,
             'XCInjectBundleInto': '__TESTHOST__/%s' % self.module_name
             }
         }
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 22418d7..4278e0a 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -278,10 +278,8 @@
     "MediaPlayer.framework",
   ]
 
-  allow_circular_includes_from = [
-    "//ios/chrome/app/application_delegate:application_delegate_internal",
-    "//ios/chrome/browser/ui/main:scene",
-  ]
+  allow_circular_includes_from =
+      [ "//ios/chrome/app/application_delegate:application_delegate_internal" ]
 }
 
 source_set("mode") {
diff --git a/ios/chrome/app/main_application_delegate.mm b/ios/chrome/app/main_application_delegate.mm
index 7daae5b..86218a8 100644
--- a/ios/chrome/app/main_application_delegate.mm
+++ b/ios/chrome/app/main_application_delegate.mm
@@ -92,11 +92,14 @@
 }
 
 - (UIWindow*)window {
-  return self.sceneState.window;
+  return [_mainController window];
 }
 
 - (void)setWindow:(UIWindow*)newWindow {
-  NOTREACHED() << "Should not be called, use [SceneState window] instead";
+  DCHECK(newWindow);
+  [_mainController setWindow:newWindow];
+  // self.window has been set by this time. _appState window can now be set.
+  [_appState setWindow:newWindow];
 }
 
 #pragma mark - UIApplicationDelegate methods -
@@ -110,10 +113,9 @@
 - (BOOL)application:(UIApplication*)application
     didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
   startup_loggers::RegisterAppDidFinishLaunchingTime();
-
-  _mainController.window = self.window;
-  // self.window has been set by this time. _appState window can now be set.
-  _appState.window = self.window;
+  // Main window must be ChromeOverlayWindow or a subclass of it.
+  self.window = [[ChromeOverlayWindow alloc]
+      initWithFrame:[[UIScreen mainScreen] bounds]];
 
   BOOL inBackground =
       [application applicationState] == UIApplicationStateBackground;
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index ae8c70f2..69cf64bb 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -52,7 +52,6 @@
 #include "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
 #include "ios/chrome/grit/ios_strings.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -324,8 +323,7 @@
       initWithBaseViewController:self.viewController];
   self.passwordBreachCoordinator.dispatcher = self.dispatcher;
 
-  self.printController = [[PrintController alloc]
-      initWithContextGetter:self.browserState->GetRequestContext()];
+  self.printController = [[PrintController alloc] init];
 
   self.qrScannerCoordinator = [[QRScannerLegacyCoordinator alloc]
       initWithBaseViewController:self.viewController];
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn
index 3bffff5..de15633 100644
--- a/ios/chrome/browser/ui/main/BUILD.gn
+++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -21,7 +21,6 @@
     "//ios/chrome/browser/tabs:tabs",
     "//ios/chrome/browser/ui/commands:commands",
     "//ios/chrome/browser/ui/tab_grid",
-    "//ios/chrome/browser/ui/util:multiwindow_util",
   ]
 
   libs = [ "UIKit.framework" ]
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index ae24261..9430b5eb 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -4,10 +4,6 @@
 
 #import "ios/chrome/browser/ui/main/scene_controller.h"
 
-#import "base/logging.h"
-#import "ios/chrome/app/chrome_overlay_window.h"
-#import "ios/chrome/browser/ui/util/multi_window_support.h"
-
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -19,14 +15,6 @@
   if (self) {
     _sceneState = sceneState;
     [_sceneState addObserver:self];
-    // The window is necessary very early in the app/scene lifecycle, so it
-    // should be created right away.
-    if (!self.sceneState.window) {
-      DCHECK(!IsMultiwindowSupported())
-          << "The window must be created by the scene delegate";
-      self.sceneState.window = [[ChromeOverlayWindow alloc]
-          initWithFrame:[[UIScreen mainScreen] bounds]];
-    }
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/main/scene_delegate.mm b/ios/chrome/browser/ui/main/scene_delegate.mm
index bc829464..76570750 100644
--- a/ios/chrome/browser/ui/main/scene_delegate.mm
+++ b/ios/chrome/browser/ui/main/scene_delegate.mm
@@ -4,9 +4,6 @@
 
 #import "ios/chrome/browser/ui/main/scene_delegate.h"
 
-#include "base/mac/foundation_util.h"
-#import "ios/chrome/app/chrome_overlay_window.h"
-
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -21,18 +18,7 @@
   return _sceneState;
 }
 
-#pragma mark - UIWindowSceneDelegate
-
-// This getter is called when the SceneDelegate is created. Returning a
-// ChromeOverlayWindow allows UIKit to use that as the main window for this
-// scene.
-- (UIWindow*)window {
-  if (!_window) {
-    // Sizing of the window is handled by UIKit.
-    _window = [[ChromeOverlayWindow alloc] init];
-  }
-  return _window;
-}
+#pragma mark - UISceneDelegate
 
 #pragma mark Connecting and Disconnecting the Scene
 
@@ -40,7 +26,6 @@
     willConnectToSession:(UISceneSession*)session
                  options:(UISceneConnectionOptions*)connectionOptions
     API_AVAILABLE(ios(13)) {
-  self.sceneState.scene = base::mac::ObjCCastStrict<UIWindowScene>(scene);
   self.sceneState.activationLevel = SceneActivationLevelBackground;
 }
 
diff --git a/ios/chrome/browser/ui/main/scene_state.h b/ios/chrome/browser/ui/main/scene_state.h
index c72ffe2..d417eda 100644
--- a/ios/chrome/browser/ui/main/scene_state.h
+++ b/ios/chrome/browser/ui/main/scene_state.h
@@ -44,9 +44,7 @@
 @property(nonatomic, assign) SceneActivationLevel activationLevel;
 
 // Window for the associated scene, if any.
-@property(nonatomic, strong) UIWindow* window;
-
-@property(nonatomic, strong) UIWindowScene* scene API_AVAILABLE(ios(13));
+@property(nonatomic, weak) UIWindow* window;
 
 // Adds an observer to this scene state. The observers will be notified about
 // scene state changes per SceneStateObserver protocol.
diff --git a/ios/chrome/browser/ui/main/scene_state.mm b/ios/chrome/browser/ui/main/scene_state.mm
index 2eb709e..286a76231 100644
--- a/ios/chrome/browser/ui/main/scene_state.mm
+++ b/ios/chrome/browser/ui/main/scene_state.mm
@@ -5,8 +5,6 @@
 #import "ios/chrome/browser/ui/main/scene_state.h"
 
 #import "base/ios/crb_protocol_observers.h"
-#import "ios/chrome/app/chrome_overlay_window.h"
-#import "ios/chrome/browser/ui/util/multi_window_support.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -28,7 +26,6 @@
 @end
 
 @implementation SceneState
-@synthesize window = _window;
 
 - (instancetype)init {
   self = [super init];
@@ -51,30 +48,6 @@
 
 #pragma mark - Setters & Getters.
 
-- (void)setWindow:(UIWindow*)window {
-  if (IsMultiwindowSupported()) {
-    // No need to set anything, instead the getter is backed by scene.windows
-    // property.
-    return;
-  }
-  _window = window;
-}
-
-- (UIWindow*)window {
-  if (IsMultiwindowSupported()) {
-    UIWindow* mainWindow = nil;
-    if (@available(ios 13, *)) {
-      for (UIWindow* window in self.scene.windows) {
-        if ([window isKindOfClass:[ChromeOverlayWindow class]]) {
-          mainWindow = window;
-        }
-      }
-    }
-    return mainWindow;
-  }
-  return _window;
-}
-
 - (void)setActivationLevel:(SceneActivationLevel)newLevel {
   if (_activationLevel == newLevel) {
     return;
diff --git a/ios/chrome/browser/ui/print/print_controller.h b/ios/chrome/browser/ui/print/print_controller.h
index 1639669..b873f30 100644
--- a/ios/chrome/browser/ui/print/print_controller.h
+++ b/ios/chrome/browser/ui/print/print_controller.h
@@ -7,22 +7,11 @@
 
 #import <UIKit/UIKit.h>
 
-#include "base/memory/ref_counted.h"
 #import "ios/chrome/browser/web/web_state_printer.h"
 
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
-
 // Interface for printing.
 @interface PrintController : NSObject <WebStatePrinter>
 
-- (instancetype)initWithContextGetter:
-    (scoped_refptr<net::URLRequestContextGetter>)getter
-    NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)init NS_UNAVAILABLE;
-
 // Shows print UI for |view| with |title|.
 - (void)printView:(UIView*)view withTitle:(NSString*)title;
 
diff --git a/ios/chrome/browser/ui/print/print_controller.mm b/ios/chrome/browser/ui/print/print_controller.mm
index 1bb665a..8ebedfe 100644
--- a/ios/chrome/browser/ui/print/print_controller.mm
+++ b/ios/chrome/browser/ui/print/print_controller.mm
@@ -4,156 +4,19 @@
 
 #import "ios/chrome/browser/ui/print/print_controller.h"
 
-#import <MobileCoreServices/UTType.h>
-#import <WebKit/WebKit.h>
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/location.h"
 #include "base/logging.h"
-#include "base/mac/foundation_util.h"
-#include "base/memory/ref_counted.h"
 #include "base/metrics/user_metrics.h"
-#include "base/metrics/user_metrics_action.h"
-#include "base/task/post_task.h"
-#include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/tabs/tab_title_util.h"
-#import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
-#import "ios/chrome/browser/ui/alert_coordinator/loading_alert_coordinator.h"
-#include "ios/chrome/grit/ios_strings.h"
 #import "ios/web/public/web_state.h"
-#import "net/base/mac/url_conversions.h"
-#include "net/http/http_response_headers.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-using net::URLFetcher;
-using net::URLFetcherDelegate;
-using net::URLRequestContextGetter;
-
-@interface PrintController ()
-
-// Presents a UIPrintInteractionController with a default completion handler.
-// |isPDF| indicates if |printInteractionController| is being presented to print
-// a PDF.
-+ (void)displayPrintInteractionController:
-            (UIPrintInteractionController*)printInteractionController
-                                   forPDF:(BOOL)isPDF;
-
-// Shows a dialog on |viewController| indicating that the print preview is being
-// prepared. The dialog will appear only if the download has not completed or
-// been cancelled |kPDFDownloadDialogDelay| seconds after this method is called.
-- (void)showPDFDownloadingDialog:(UIViewController*)viewController;
-
-// Dismisses the dialog which indicates that the print preview is being
-// prepared.
-- (void)dismissPDFDownloadingDialog;
-
-// Shows an dialog on |viewController| indicating that there was an error when
-// preparing the print preview, and providing the ability to retry. |URL| is the
-// URL of the PDF which had an error.
-- (void)showPDFDownloadErrorWithURL:(const GURL)URL
-                     viewController:(UIViewController*)viewController;
-
-// Handles downloading the file at |URL| and presents dialogs on
-// |viewController| if necessary.
-- (void)downloadPDFFileWithURL:(const GURL&)URL
-                viewController:(UIViewController*)viewController;
-
-// Accesses the result of the PDF download, and if successful, presents the
-// AirPrint menu with the downloaded PDF. It also ensures that the
-// PDFDownloadingDialog is dismissed, and presents an error dialog on
-// |viewController| if the download fails. This method should be called only by
-// the URLFetcherDelegate.
-- (void)finishedDownloadingPDF:(UIViewController*)viewController;
-
-@end
-
-namespace {
-
-// The MIME type of a PDF file contained in a Web view.
-const char kPDFMimeType[] = "application/pdf";
-
-// Delay after downloading begins that the |_PDFDownloadingDialog| appears.
-const int64_t kPDFDownloadDialogDelay = 1;
-
-// A delegate for the URLFetcher to tell owning PrintController that the
-// download is complete.
-class PrintPDFFetcherDelegate : public URLFetcherDelegate {
- public:
-  explicit PrintPDFFetcherDelegate(PrintController* owner) : owner_(owner) {}
-  void OnURLFetchComplete(const URLFetcher* source) override {
-    DCHECK(view_controller_);
-    [owner_ finishedDownloadingPDF:view_controller_];
-  }
-
-  // The ViewController used to display an error if the download failed.
-  void SetViewController(UIViewController* view_controller) {
-    view_controller_ = view_controller;
-  }
-
- private:
-  __weak PrintController* owner_;
-  __weak UIViewController* view_controller_;
-  DISALLOW_COPY_AND_ASSIGN(PrintPDFFetcherDelegate);
-};
-}  // namespace
-
-@implementation PrintController {
-  // URLFetcher to download the PDF pointed to by the WKWebView.
-  std::unique_ptr<URLFetcher> _fetcher;
-
-  // A delegate to bridge between PrintController and the URLFetcher callback.
-  std::unique_ptr<PrintPDFFetcherDelegate> _fetcherDelegate;
-
-  // Context getter required by the URLFetcher.
-  scoped_refptr<URLRequestContextGetter> _requestContextGetter;
-
-  // A dialog which indicates that the print preview is being prepared. It
-  // offers a cancel button which will cancel the download. It is created when
-  // downloading begins and is released when downloading ends (either due to
-  // cancellation or completion).
-  LoadingAlertCoordinator* _PDFDownloadingDialog;
-
-  // A dialog which indicates that the print preview failed.
-  AlertCoordinator* _PDFDownloadingErrorDialog;
-}
-
-#pragma mark - Class methods.
-
-+ (void)displayPrintInteractionController:
-            (UIPrintInteractionController*)printInteractionController
-                                   forPDF:(BOOL)isPDF {
-  void (^completionHandler)(UIPrintInteractionController*, BOOL, NSError*) = ^(
-      UIPrintInteractionController* printInteractionController, BOOL completed,
-      NSError* error) {
-    if (error)
-      DLOG(ERROR) << "Air printing error: " << error.description;
-  };
-  [printInteractionController presentAnimated:YES
-                            completionHandler:completionHandler];
-}
+@implementation PrintController
 
 #pragma mark - Public Methods
 
-- (instancetype)initWithContextGetter:
-    (scoped_refptr<net::URLRequestContextGetter>)getter {
-  self = [super init];
-  if (self) {
-    _requestContextGetter = std::move(getter);
-    _fetcherDelegate.reset(new PrintPDFFetcherDelegate(self));
-  }
-  return self;
-}
-
 - (void)printView:(UIView*)view withTitle:(NSString*)title {
   base::RecordAction(base::UserMetricsAction("MobilePrintMenuAirPrint"));
   UIPrintInteractionController* printInteractionController =
@@ -167,15 +30,18 @@
   [renderer addPrintFormatter:[view viewPrintFormatter]
         startingAtPageAtIndex:0];
   printInteractionController.printPageRenderer = renderer;
-  [PrintController displayPrintInteractionController:printInteractionController
-                                              forPDF:NO];
+
+  [printInteractionController
+        presentAnimated:YES
+      completionHandler:^(
+          UIPrintInteractionController* printInteractionController,
+          BOOL completed, NSError* error) {
+        if (error)
+          DLOG(ERROR) << "Air printing error: " << error.description;
+      }];
 }
 
 - (void)dismissAnimated:(BOOL)animated {
-  _fetcher.reset();
-  [self dismissPDFDownloadingDialog];
-  [_PDFDownloadingErrorDialog stop];
-  _PDFDownloadingErrorDialog = nil;
   [[UIPrintInteractionController sharedPrintController]
       dismissAnimated:animated];
 }
@@ -187,111 +53,4 @@
         withTitle:tab_util::GetTabTitle(webState)];
 }
 
-#pragma mark - Private Methods
-
-- (void)showPDFDownloadingDialog:(UIViewController*)viewController {
-  if (_PDFDownloadingDialog)
-    return;
-
-  NSString* title = l10n_util::GetNSString(IDS_IOS_PRINT_PDF_PREPARATION);
-
-  __weak PrintController* weakSelf = self;
-  ProceduralBlock cancelHandler = ^{
-    PrintController* strongSelf = weakSelf;
-    if (strongSelf)
-      strongSelf->_fetcher.reset();
-  };
-
-  _PDFDownloadingDialog = [[LoadingAlertCoordinator alloc]
-      initWithBaseViewController:viewController
-                           title:title
-                   cancelHandler:cancelHandler];
-
-  dispatch_after(
-      dispatch_time(DISPATCH_TIME_NOW, kPDFDownloadDialogDelay * NSEC_PER_SEC),
-      dispatch_get_main_queue(), ^{
-        PrintController* strongSelf = weakSelf;
-        if (!strongSelf)
-          return;
-        [strongSelf->_PDFDownloadingDialog start];
-      });
-}
-
-- (void)dismissPDFDownloadingDialog {
-  [_PDFDownloadingDialog stop];
-  _PDFDownloadingDialog = nil;
-}
-
-- (void)showPDFDownloadErrorWithURL:(const GURL)URL
-                     viewController:(UIViewController*)viewController {
-  NSString* title = l10n_util::GetNSString(IDS_IOS_PRINT_PDF_ERROR_TITLE);
-  NSString* message = l10n_util::GetNSString(IDS_IOS_PRINT_PDF_ERROR_SUBTITLE);
-
-  _PDFDownloadingErrorDialog =
-      [[AlertCoordinator alloc] initWithBaseViewController:viewController
-                                                     title:title
-                                                   message:message];
-
-  __weak PrintController* weakSelf = self;
-
-  [_PDFDownloadingErrorDialog
-      addItemWithTitle:l10n_util::GetNSString(IDS_IOS_PRINT_PDF_TRY_AGAIN)
-                action:^{
-                  [weakSelf downloadPDFFileWithURL:URL
-                                    viewController:viewController];
-                }
-                 style:UIAlertActionStyleDefault];
-
-  [_PDFDownloadingErrorDialog
-      addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
-                action:nil
-                 style:UIAlertActionStyleCancel];
-
-  [_PDFDownloadingErrorDialog start];
-}
-
-- (void)downloadPDFFileWithURL:(const GURL&)URL
-                viewController:(UIViewController*)viewController {
-  DCHECK(!_fetcher);
-  _fetcherDelegate->SetViewController(viewController);
-  _fetcher = URLFetcher::Create(URL, URLFetcher::GET, _fetcherDelegate.get());
-  _fetcher->SetRequestContext(_requestContextGetter.get());
-  _fetcher->Start();
-  [self showPDFDownloadingDialog:viewController];
-}
-
-- (void)finishedDownloadingPDF:(UIViewController*)viewController {
-  [self dismissPDFDownloadingDialog];
-  DCHECK(_fetcher);
-  base::ScopedClosureRunner fetcherResetter(base::BindOnce(^{
-    _fetcher.reset();
-  }));
-  int responseCode = _fetcher->GetResponseCode();
-  std::string response;
-  std::string MIMEType;
-  // If the request is not successful or does not match a PDF
-  // MIME type, show an error.
-  if (!_fetcher->GetStatus().is_success() || responseCode != 200 ||
-      !_fetcher->GetResponseAsString(&response) ||
-      !_fetcher->GetResponseHeaders()->GetMimeType(&MIMEType) ||
-      MIMEType != kPDFMimeType) {
-    [self showPDFDownloadErrorWithURL:_fetcher->GetOriginalURL()
-                       viewController:viewController];
-    return;
-  }
-  NSData* data =
-      [NSData dataWithBytes:response.c_str() length:response.length()];
-  // If the data cannot be printed, show an error.
-  if (![UIPrintInteractionController canPrintData:data]) {
-    [self showPDFDownloadErrorWithURL:_fetcher->GetOriginalURL()
-                       viewController:viewController];
-    return;
-  }
-  UIPrintInteractionController* printInteractionController =
-      [UIPrintInteractionController sharedPrintController];
-  printInteractionController.printingItem = data;
-  [PrintController displayPrintInteractionController:printInteractionController
-                                              forPDF:YES];
-}
-
 @end
diff --git a/ios/chrome/browser/ui/sad_tab/BUILD.gn b/ios/chrome/browser/ui/sad_tab/BUILD.gn
index bdae456..a6ed853 100644
--- a/ios/chrome/browser/ui/sad_tab/BUILD.gn
+++ b/ios/chrome/browser/ui/sad_tab/BUILD.gn
@@ -76,6 +76,7 @@
 }
 
 source_set("eg_tests") {
+  defines = [ "CHROME_EARL_GREY_1" ]
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
@@ -97,3 +98,30 @@
   ]
   libs = [ "XCTest.framework" ]
 }
+
+source_set("eg2_tests") {
+  defines = [ "CHROME_EARL_GREY_2" ]
+  configs += [
+    "//build/config/compiler:enable_arc",
+    "//build/config/ios:xctest_config",
+  ]
+  testonly = true
+  sources = [
+    "sad_tab_view_egtest.mm",
+  ]
+
+  deps = [
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui/popup_menu:constants",
+    "//ios/chrome/test:eg_test_support+eg2",
+    "//ios/chrome/test/earl_grey:eg_test_support+eg2",
+    "//ios/testing:embedded_test_server_support",
+    "//ios/testing/earl_grey:eg_test_support+eg2",
+    "//ios/third_party/earl_grey2:test_lib",
+    "//ios/web/public/test/http_server",
+    "//ui/base",
+  ]
+
+  libs = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_view_egtest.mm b/ios/chrome/browser/ui/sad_tab/sad_tab_view_egtest.mm
index 03c2b02..b5b1790 100644
--- a/ios/chrome/browser/ui/sad_tab/sad_tab_view_egtest.mm
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_view_egtest.mm
@@ -2,16 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import <EarlGrey/EarlGrey.h>
-#import <XCTest/XCTest.h>
-
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
-#import "ios/chrome/test/app/chrome_test_util.h"
+#import "ios/chrome/test/earl_grey/chrome_actions.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#import "ios/testing/earl_grey/earl_grey_test.h"
 #import "ios/web/public/test/http_server/http_server.h"
 #include "ios/web/public/test/http_server/http_server_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
@@ -24,53 +22,36 @@
 // Returns matcher that looks for text in UILabel, UITextView, and UITextField
 // objects, checking if their displayed strings contain the provided |text|.
 id<GREYMatcher> ContainsText(NSString* text) {
-  MatchesBlock matches = ^BOOL(id element) {
+  GREYMatchesBlock matches = ^BOOL(id element) {
     return [[element text] containsString:text];
   };
-  DescribeToBlock describe = ^void(id<GREYDescription> description) {
+  GREYDescribeToBlock describe = ^void(id<GREYDescription> description) {
     [description appendText:[NSString stringWithFormat:@"hasText('%@')", text]];
   };
   id<GREYMatcher> matcher =
       [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches
                                            descriptionBlock:describe];
-  return grey_allOf(grey_anyOf(grey_kindOfClass([UILabel class]),
-                               grey_kindOfClass([UITextField class]),
-                               grey_kindOfClass([UITextView class]), nil),
+  return grey_allOf(grey_anyOf(grey_kindOfClassName(@"UILabel"),
+                               grey_kindOfClassName(@"UITextField"),
+                               grey_kindOfClassName(@"UITextView"), nil),
                     matcher, nil);
 }
 
 // A matcher for the main title of the Sad Tab in 'reload' mode.
 id<GREYMatcher> reloadSadTabTitleText() {
-  static id matcher = nil;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    matcher = [GREYMatchers
-        matcherForText:l10n_util::GetNSString(IDS_SAD_TAB_MESSAGE)];
-  });
-  return matcher;
+  return ContainsText(l10n_util::GetNSString(IDS_SAD_TAB_MESSAGE));
 }
 
 // A matcher for the main title of the Sad Tab in 'feedback' mode.
 id<GREYMatcher> feedbackSadTabTitleContainsText() {
-  static id matcher = nil;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    matcher = ContainsText(l10n_util::GetNSString(IDS_SAD_TAB_RELOAD_TRY));
-  });
-  return matcher;
+  return ContainsText(l10n_util::GetNSString(IDS_SAD_TAB_RELOAD_TRY));
 }
 
 // A matcher for a help string suggesting the user use Incognito Mode.
 id<GREYMatcher> incognitoHelpContainsText() {
-  static id matcher = nil;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    matcher =
-        ContainsText(l10n_util::GetNSString(IDS_SAD_TAB_RELOAD_INCOGNITO));
-  });
-  return matcher;
+  return ContainsText(l10n_util::GetNSString(IDS_SAD_TAB_RELOAD_INCOGNITO));
 }
-}
+}  // namespace
 
 // Sad Tab View integration tests for Chrome.
 @interface SadTabViewTestCase : ChromeTestCase
diff --git a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
index fc4c568..1458708 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
@@ -1556,8 +1556,10 @@
     [[EarlGrey
         selectElementWithMatcher:grey_allOf(
                                      ButtonWithAccessibilityLabel(dismissLabel),
-                                     grey_interactable(), nullptr)]
-        performAction:grey_tap()];
+                                     grey_interactable(),
+                                     grey_not(grey_accessibilityTrait(
+                                         UIAccessibilityTraitNotEnabled)),
+                                     nullptr)] performAction:grey_tap()];
   }
 
   // Wait until the activity view is dismissed.
diff --git a/ios/chrome/browser/web/child_window_open_by_dom_egtest.mm b/ios/chrome/browser/web/child_window_open_by_dom_egtest.mm
index 64f90b9a..a5c9bbd 100644
--- a/ios/chrome/browser/web/child_window_open_by_dom_egtest.mm
+++ b/ios/chrome/browser/web/child_window_open_by_dom_egtest.mm
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/content_settings/core/common/content_settings.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
@@ -10,11 +11,14 @@
 #import "ios/testing/earl_grey/earl_grey_test.h"
 #import "ios/web/public/test/http_server/http_server.h"
 #include "ios/web/public/test/http_server/http_server_util.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+using chrome_test_util::OmniboxText;
 using web::test::HttpServer;
 
 namespace {
@@ -29,6 +33,34 @@
 const char kWindow1Closed[] = "window1.closed: true";
 const char kWindow2Closed[] = "window2.closed: true";
 
+// URLs for testWindowOpenWriteAndReload.
+const char kWriteReloadPath[] = "/writeReload.html";
+const char kSlowPath[] = "/slow.html";
+const char kSlowPathContent[] = "Slow Page";
+int kSlowPathDelay = 3;
+
+// net::EmbeddedTestServer handler for kWriteReloadPath and kSlowPath.
+std::unique_ptr<net::test_server::HttpResponse> WriteReloadHandler(
+    const net::test_server::HttpRequest& request) {
+  if (request.GetURL().path() == kSlowPath) {
+    auto slow_http_response =
+        std::make_unique<net::test_server::DelayedHttpResponse>(
+            base::TimeDelta::FromSeconds(kSlowPathDelay));
+    slow_http_response->set_content_type("text/html");
+    slow_http_response->set_content(kSlowPathContent);
+    return std::move(slow_http_response);
+  }
+  auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
+  http_response->set_content_type("text/html");
+  http_response->set_content(base::StringPrintf(
+      "<html><body><script>function start(){var x = window.open('javascript"
+      ":document.write(1)');setTimeout(function(){x.location='%s'}, "
+      "500);};</script><input onclick='start()' id='button' value='button' "
+      "type='button' /></body></html>",
+      kSlowPath));
+  return std::move(http_response);
+}
+
 }  // namespace
 
 // Test case for child windows opened by DOM.
@@ -208,4 +240,20 @@
   [ChromeEarlGrey waitForWebStateContainingText:kWindow2Closed];
 }
 
+// Tests that reloading a window.open with a document.write does not leave a
+// dangling pending item. This is a regression test from crbug.com/1011898
+- (void)testWindowOpenWriteAndReload {
+  self.testServer->RegisterRequestHandler(base::Bind(&WriteReloadHandler));
+  GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
+  [ChromeEarlGrey loadURL:self.testServer->GetURL(kWriteReloadPath)];
+  [ChromeEarlGrey tapWebStateElementWithID:@"button"];
+  [ChromeEarlGrey reload];
+  [ChromeEarlGrey waitForWebStateContainingText:kSlowPathContent
+                                        timeout:kSlowPathDelay * 2];
+
+  GURL slowURL = self.testServer->GetURL(kSlowPath);
+  [[EarlGrey selectElementWithMatcher:OmniboxText(slowURL.GetContent())]
+      assertWithMatcher:grey_notNil()];
+}
+
 @end
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index 4008af2..970e902 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -266,6 +266,7 @@
     "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/test/app:test_support",
+    "//ios/testing:verify_custom_webkit",
     "//ios/testing/earl_grey:earl_grey_support",
     "//ios/third_party/material_components_ios",
     "//ios/third_party/webkit",
@@ -374,6 +375,7 @@
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/test/app:test_support",
     "//ios/testing:nserror_support",
+    "//ios/testing:verify_custom_webkit",
     "//ios/testing/earl_grey:eg_app_support+eg2",
     "//ios/third_party/earl_grey2:app_framework+link",
     "//ios/third_party/gtx:gtx+link",
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.h b/ios/chrome/test/earl_grey/chrome_earl_grey.h
index 10a4121aa..fa394653 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.h
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.h
@@ -384,6 +384,11 @@
 // Returns YES if CreditCardScanner feature is enabled.
 - (BOOL)isCreditCardScannerEnabled WARN_UNUSED_RESULT;
 
+// Returns YES if custom WebKit frameworks were properly loaded, rather than
+// system frameworks. Always returns YES if the app was not requested to run
+// with custom WebKit frameworks.
+- (BOOL)isCustomWebKitLoadedIfRequested WARN_UNUSED_RESULT;
+
 #pragma mark - Popup Blocking
 
 // Gets the current value of the popup content setting preference for the
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.mm b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
index 391aa0e..6bb0fff 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
@@ -647,6 +647,10 @@
   return [ChromeEarlGreyAppInterface isCreditCardScannerEnabled];
 }
 
+- (BOOL)isCustomWebKitLoadedIfRequested {
+  return [ChromeEarlGreyAppInterface isCustomWebKitLoadedIfRequested];
+}
+
 #pragma mark - ScopedBlockPopupsPref
 
 - (ContentSetting)popupPrefValue {
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
index 8b8c880..cf68667 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
@@ -313,6 +313,11 @@
 // Returns YES if CreditCardScanner feature is enabled.
 + (BOOL)isCreditCardScannerEnabled WARN_UNUSED_RESULT;
 
+// Returns YES if custom WebKit frameworks were properly loaded, rather than
+// system frameworks. Always returns YES if the app was not requested to run
+// with custom WebKit frameworks.
++ (BOOL)isCustomWebKitLoadedIfRequested WARN_UNUSED_RESULT;
+
 #pragma mark - Popup Blocking
 
 // Gets the current value of the popup content setting preference for the
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
index 5efb7c8..e57cac9 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
@@ -25,6 +25,7 @@
 #import "ios/chrome/test/app/tab_test_util.h"
 #import "ios/chrome/test/earl_grey/accessibility_util.h"
 #import "ios/testing/nserror_util.h"
+#include "ios/testing/verify_custom_webkit.h"
 #import "ios/web/common/features.h"
 #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
 #import "ios/web/public/navigation/navigation_manager.h"
@@ -537,6 +538,10 @@
   return base::FeatureList::IsEnabled(kCreditCardScanner);
 }
 
++ (BOOL)isCustomWebKitLoadedIfRequested {
+  return IsCustomWebKitLoadedIfRequested();
+}
+
 #pragma mark - ScopedBlockPopupsPref
 
 + (ContentSetting)popupPrefValue {
diff --git a/ios/chrome/test/earl_grey/chrome_test_case.mm b/ios/chrome/test/earl_grey/chrome_test_case.mm
index 8c7fb7d..c5748f9 100644
--- a/ios/chrome/test/earl_grey/chrome_test_case.mm
+++ b/ios/chrome/test/earl_grey/chrome_test_case.mm
@@ -408,6 +408,8 @@
 // Dismisses and revert browser settings to default.
 // It also starts the HTTP server and enables mock authentication.
 + (void)setUpHelper {
+  XCTAssertTrue([ChromeEarlGrey isCustomWebKitLoadedIfRequested]);
+
   [CoverageUtils configureCoverageReportPath];
 
   [[self class] startHTTPServer];
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn
index 9f9940c..4058e65 100644
--- a/ios/chrome/test/earl_grey2/BUILD.gn
+++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -46,6 +46,7 @@
     "//ios/chrome/browser/ui/omnibox/popup/shortcuts:eg2_tests",
     "//ios/chrome/browser/ui/open_in:eg2_tests",
     "//ios/chrome/browser/ui/page_info:eg2_tests",
+    "//ios/chrome/browser/ui/sad_tab:eg2_tests",
     "//ios/chrome/browser/ui/settings/autofill:eg2_tests",
     "//ios/chrome/browser/ui/toolbar:eg2_tests",
   ]
diff --git a/ios/net/cookies/cookie_store_ios_unittest.mm b/ios/net/cookies/cookie_store_ios_unittest.mm
index efd7dc172..f18d595c 100644
--- a/ios/net/cookies/cookie_store_ios_unittest.mm
+++ b/ios/net/cookies/cookie_store_ios_unittest.mm
@@ -69,6 +69,7 @@
   static const bool has_exact_change_cause = false;
   static const bool has_exact_change_ordering = false;
   static const int creation_time_granularity_in_ms = 1000;
+  static const bool supports_cookie_access_semantics = false;
 
   base::test::SingleThreadTaskEnvironment task_environment_;
 };
diff --git a/ios/testing/BUILD.gn b/ios/testing/BUILD.gn
index 4c12d39..c7b574d 100644
--- a/ios/testing/BUILD.gn
+++ b/ios/testing/BUILD.gn
@@ -12,6 +12,18 @@
   ]
 }
 
+source_set("verify_custom_webkit") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "verify_custom_webkit.h",
+    "verify_custom_webkit.mm",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
 source_set("nserror_support") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
diff --git a/ios/testing/verify_custom_webkit.h b/ios/testing/verify_custom_webkit.h
new file mode 100644
index 0000000..6f1a2e43
--- /dev/null
+++ b/ios/testing/verify_custom_webkit.h
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_TESTING_VERIFY_CUSTOM_WEBKIT_H_
+#define IOS_TESTING_VERIFY_CUSTOM_WEBKIT_H_
+
+// Returns whether custom WebKit frameworks were loaded if
+// --run-with-custom-webkit was passed on the commandline.  Otherwise, always
+// returns true.
+bool IsCustomWebKitLoadedIfRequested();
+
+#endif  // IOS_TESTING_VERIFY_CUSTOM_WEBKIT_H_
diff --git a/ios/testing/verify_custom_webkit.mm b/ios/testing/verify_custom_webkit.mm
new file mode 100644
index 0000000..aae09a9
--- /dev/null
+++ b/ios/testing/verify_custom_webkit.mm
@@ -0,0 +1,58 @@
+// 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.
+
+#import "ios/testing/verify_custom_webkit.h"
+
+#import <Foundation/Foundation.h>
+#include <mach-o/dyld.h>
+
+#include "base/command_line.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+// The switch used when running with custom WebKit frameworks.
+const char kRunWithCustomWebKit[] = "run-with-custom-webkit";
+
+}
+
+bool IsCustomWebKitLoadedIfRequested() {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          kRunWithCustomWebKit)) {
+    return true;
+  }
+
+  bool foundIncorrectLoadLocation = false;
+  NSArray<NSString*>* frameworks = @[
+    @"JavaScriptCore.framework/JavaScriptCore",
+    @"WebCore.framework/WebCore",
+    @"WebKit.framework/WebKit",
+    @"WebKitLegacy.framework/WebKitLegacy",
+  ];
+
+  uint32_t numImages = _dyld_image_count();
+  for (uint32_t i = 0; i < numImages; i++) {
+    NSString* imagePath =
+        [NSString stringWithUTF8String:_dyld_get_image_name(i)];
+    for (NSString* framework in frameworks) {
+      if ([imagePath containsString:framework]) {
+        // Custom frameworks are bundled inside a "WebKitFrameworks"
+        // subdirectory, so look for that string to be present in |full_path|.
+        if (![imagePath containsString:@"WebKitFrameworks"]) {
+          // This framework was loaded from an unexpected location.
+          NSLog(@"Unexpectedly loaded %@ from %@ ", framework, imagePath);
+          foundIncorrectLoadLocation = true;
+        }
+      }
+    }
+  }
+
+  // Note that checks are not performed on frameworks that were never loaded at
+  // all.  This function checks that *if* they were loaded, they were loaded
+  // from the correct location.
+  return !foundIncorrectLoadLocation;
+}
diff --git a/ios/web/test/BUILD.gn b/ios/web/test/BUILD.gn
index 00e02840..939a26f4 100644
--- a/ios/web/test/BUILD.gn
+++ b/ios/web/test/BUILD.gn
@@ -58,6 +58,7 @@
     ":test_constants",
     "//base",
     "//base/test:test_support",
+    "//ios/testing:verify_custom_webkit",
     "//ios/web",
     "//ios/web/common:web_view_creation_util",
     "//ios/web/navigation:core",
diff --git a/ios/web/test/web_test_suite.mm b/ios/web/test/web_test_suite.mm
index 74a51d6..45dd1f2 100644
--- a/ios/web/test/web_test_suite.mm
+++ b/ios/web/test/web_test_suite.mm
@@ -4,8 +4,10 @@
 
 #include "ios/web/public/test/web_test_suite.h"
 
+#include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
+#include "ios/testing/verify_custom_webkit.h"
 #include "ios/web/public/navigation/url_schemes.h"
 #import "ios/web/public/test/fakes/test_web_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -19,9 +21,15 @@
 
 WebTestSuite::WebTestSuite(int argc, char** argv)
     : base::TestSuite(argc, argv),
-      web_client_(base::WrapUnique(new TestWebClient)) {}
+      web_client_(base::WrapUnique(new TestWebClient)) {
+  CHECK(IsCustomWebKitLoadedIfRequested());
+}
 
-WebTestSuite::~WebTestSuite() {}
+WebTestSuite::~WebTestSuite() {
+  // Verify again at the end of the test run, in case some frameworks were not
+  // yet loaded when the constructor ran.
+  CHECK(IsCustomWebKitLoadedIfRequested());
+}
 
 void WebTestSuite::Initialize() {
   base::TestSuite::Initialize();
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 861828d..51d93f9 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -941,6 +941,7 @@
 
 - (void)setDocumentURL:(const GURL&)newURL
                context:(web::NavigationContextImpl*)context {
+  GURL oldDocumentURL = _documentURL;
   if (newURL != _documentURL && newURL.is_valid()) {
     _documentURL = newURL;
     _userInteractionState.SetUserInteractionRegisteredSinceLastUrlChange(false);
@@ -949,6 +950,16 @@
       !context->IsLoadingHtmlString() && !context->IsLoadingErrorPage() &&
       !IsWKInternalUrl(newURL) && !newURL.SchemeIs(url::kAboutScheme) &&
       self.webView) {
+    // On iOS13, WebKit started changing the URL visible webView.URL when
+    // opening a new tab and then writing to it, e.g.
+    // window.open('javascript:document.write(1)').  This URL is never commited,
+    // so it should be OK to ignore this URL change.
+    if (base::ios::IsRunningOnIOS13OrLater() && oldDocumentURL.IsAboutBlank() &&
+        !self.webStateImpl->GetNavigationManager()->GetLastCommittedItem() &&
+        !self.webView.loading) {
+      return;
+    }
+
     GURL documentOrigin = newURL.GetOrigin();
     web::NavigationItem* committedItem =
         self.webStateImpl->GetNavigationManager()->GetLastCommittedItem();
@@ -1930,7 +1941,8 @@
   if (!IsRestoreSessionUrl(_documentURL) && !IsRestoreSessionUrl(newURL)) {
     bool ignore_host_change =
         // On iOS13 document.write() can change URL origin for about:blank page.
-        (_documentURL.IsAboutBlank() && base::ios::IsRunningOnIOS13OrLater());
+        (_documentURL.IsAboutBlank() && base::ios::IsRunningOnIOS13OrLater() &&
+         !self.webView.loading);
     if (!ignore_host_change) {
       DCHECK_EQ(_documentURL.host(), newURL.host());
     }
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 3bda8541..8425327 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -43,7 +43,8 @@
 // Static constexpr class for generating unique identifiers for each VideoFrame.
 static base::AtomicSequenceNumber g_unique_id_generator;
 
-static std::string StorageTypeToString(
+// static
+std::string VideoFrame::StorageTypeToString(
     const VideoFrame::StorageType storage_type) {
   switch (storage_type) {
     case VideoFrame::STORAGE_UNKNOWN:
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index eebca84..9ea6ceb 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -359,6 +359,9 @@
   // E.g. 2x2 for the U-plane in PIXEL_FORMAT_I420.
   static gfx::Size SampleSize(VideoPixelFormat format, size_t plane);
 
+  // Returns a human readable string of StorageType.
+  static std::string StorageTypeToString(VideoFrame::StorageType storage_type);
+
   // A video frame wrapping external data may be backed by an unsafe shared
   // memory region. These methods are used to appropriately transform a
   // VideoFrame created with WrapExternalData, WrapExternalYuvaData, etc. The
diff --git a/media/fuchsia/cdm/fuchsia_stream_decryptor.cc b/media/fuchsia/cdm/fuchsia_stream_decryptor.cc
index c63c7c3..6ecabe2 100644
--- a/media/fuchsia/cdm/fuchsia_stream_decryptor.cc
+++ b/media/fuchsia/cdm/fuchsia_stream_decryptor.cc
@@ -92,14 +92,20 @@
     fuchsia::media::StreamProcessorPtr processor)
     : processor_(std::move(processor), this) {}
 
-FuchsiaStreamDecryptorBase::~FuchsiaStreamDecryptorBase() = default;
+FuchsiaStreamDecryptorBase::~FuchsiaStreamDecryptorBase() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
 
 void FuchsiaStreamDecryptorBase::DecryptInternal(
     scoped_refptr<DecoderBuffer> encrypted) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   input_writer_queue_.EnqueueBuffer(std::move(encrypted));
 }
 
 void FuchsiaStreamDecryptorBase::ResetStream() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   // Close current stream and drop all the cached decoder buffers.
   // Keep input and output buffers to avoid buffer re-allocation.
   processor_.Reset();
@@ -109,6 +115,8 @@
 // StreamProcessorHelper::Client implementation:
 void FuchsiaStreamDecryptorBase::AllocateInputBuffers(
     const fuchsia::media::StreamBufferConstraints& stream_constraints) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   base::Optional<fuchsia::sysmem::BufferCollectionConstraints>
       buffer_constraints =
           SysmemBufferWriter::GetRecommendedConstraints(stream_constraints);
@@ -128,10 +136,14 @@
 }
 
 void FuchsiaStreamDecryptorBase::OnOutputFormat(
-    fuchsia::media::StreamOutputFormat format) {}
+    fuchsia::media::StreamOutputFormat format) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
 
 void FuchsiaStreamDecryptorBase::OnInputBufferPoolCreated(
     std::unique_ptr<SysmemBufferPool> pool) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (!pool) {
     DLOG(ERROR) << "Fail to allocate input buffer.";
     OnError();
@@ -150,6 +162,8 @@
 
 void FuchsiaStreamDecryptorBase::OnWriterCreated(
     std::unique_ptr<SysmemBufferWriter> writer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (!writer) {
     OnError();
     return;
@@ -166,6 +180,8 @@
 void FuchsiaStreamDecryptorBase::SendInputPacket(
     const DecoderBuffer* buffer,
     StreamProcessorHelper::IoPacket packet) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (!packet.unit_end()) {
     // The encrypted data size is too big. Decryptor should consider
     // splitting the buffer and update the IV and subsample entries.
@@ -181,6 +197,8 @@
 }
 
 void FuchsiaStreamDecryptorBase::ProcessEndOfStream() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   processor_.ProcessEos();
 }
 
@@ -208,13 +226,17 @@
 void FuchsiaClearStreamDecryptor::Decrypt(
     scoped_refptr<DecoderBuffer> encrypted,
     Decryptor::DecryptCB decrypt_cb) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!decrypt_cb_);
+
   decrypt_cb_ = std::move(decrypt_cb);
   current_status_ = Decryptor::kSuccess;
   DecryptInternal(std::move(encrypted));
 }
 
 void FuchsiaClearStreamDecryptor::CancelDecrypt() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   ResetStream();
 
   // Fire |decrypt_cb_| immediately as required by Decryptor::CancelDecrypt.
@@ -224,6 +246,8 @@
 
 void FuchsiaClearStreamDecryptor::AllocateOutputBuffers(
     const fuchsia::media::StreamBufferConstraints& stream_constraints) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (!stream_constraints.has_packet_count_for_client_max() ||
       !stream_constraints.has_packet_count_for_client_min()) {
     DLOG(ERROR) << "StreamBufferConstraints doesn't contain required fields.";
@@ -247,12 +271,15 @@
 }
 
 void FuchsiaClearStreamDecryptor::OnProcessEos() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   // Decryptor never pushes EOS frame.
   NOTREACHED();
 }
 
 void FuchsiaClearStreamDecryptor::OnOutputPacket(
     StreamProcessorHelper::IoPacket packet) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(decrypt_cb_);
 
   DCHECK(output_reader_);
@@ -312,6 +339,8 @@
 }
 
 void FuchsiaClearStreamDecryptor::OnNoKey() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   // Reset the queue. The client is expected to call Decrypt() with the same
   // buffer again when it gets kNoKey.
   input_writer_queue_.ResetQueue();
@@ -321,6 +350,8 @@
 }
 
 void FuchsiaClearStreamDecryptor::OnError() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   ResetStream();
   if (decrypt_cb_)
     std::move(decrypt_cb_).Run(Decryptor::kError, nullptr);
@@ -330,6 +361,8 @@
     size_t num_buffers_for_client,
     size_t num_buffers_for_server,
     std::unique_ptr<SysmemBufferPool> pool) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (!pool) {
     LOG(ERROR) << "Fail to allocate output buffer.";
     OnError();
@@ -351,6 +384,8 @@
 
 void FuchsiaClearStreamDecryptor::OnOutputBufferPoolReaderCreated(
     std::unique_ptr<SysmemBufferReader> reader) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (!reader) {
     LOG(ERROR) << "Fail to enable output buffer reader.";
     OnError();
@@ -372,6 +407,7 @@
     fuchsia::sysmem::BufferCollectionTokenPtr token,
     size_t num_buffers_for_decryptor,
     size_t num_buffers_for_codec) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!complete_buffer_allocation_callback_);
   complete_buffer_allocation_callback_ =
       base::BindOnce(&StreamProcessorHelper::CompleteOutputBuffersAllocation,
@@ -385,16 +421,22 @@
 
 void FuchsiaSecureStreamDecryptor::Decrypt(
     scoped_refptr<DecoderBuffer> encrypted) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   DecryptInternal(std::move(encrypted));
 }
 
 void FuchsiaSecureStreamDecryptor::Reset() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   ResetStream();
   waiting_for_key_ = false;
 }
 
 void FuchsiaSecureStreamDecryptor::AllocateOutputBuffers(
     const fuchsia::media::StreamBufferConstraints& stream_constraints) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (complete_buffer_allocation_callback_) {
     std::move(complete_buffer_allocation_callback_).Run();
   } else {
@@ -403,20 +445,28 @@
 }
 
 void FuchsiaSecureStreamDecryptor::OnProcessEos() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   client_->OnDecryptorEndOfStreamPacket();
 }
 
 void FuchsiaSecureStreamDecryptor::OnOutputPacket(
     StreamProcessorHelper::IoPacket packet) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   client_->OnDecryptorOutputPacket(std::move(packet));
 }
 
 base::RepeatingClosure FuchsiaSecureStreamDecryptor::GetOnNewKeyClosure() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   return BindToCurrentLoop(base::BindRepeating(
       &FuchsiaSecureStreamDecryptor::OnNewKey, weak_factory_.GetWeakPtr()));
 }
 
 void FuchsiaSecureStreamDecryptor::OnError() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   ResetStream();
 
   // No need to reset other fields since OnError() is called for non-recoverable
@@ -426,6 +476,7 @@
 }
 
 void FuchsiaSecureStreamDecryptor::OnNoKey() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!waiting_for_key_);
 
   // Reset stream position, but keep all pending buffers. They will be
@@ -443,6 +494,8 @@
 }
 
 void FuchsiaSecureStreamDecryptor::OnNewKey() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (!waiting_for_key_) {
     retry_on_no_key_ = true;
     return;
diff --git a/media/fuchsia/cdm/fuchsia_stream_decryptor.h b/media/fuchsia/cdm/fuchsia_stream_decryptor.h
index 594a3ef..60cc73d4 100644
--- a/media/fuchsia/cdm/fuchsia_stream_decryptor.h
+++ b/media/fuchsia/cdm/fuchsia_stream_decryptor.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "base/sequence_checker.h"
 #include "media/base/decryptor.h"
 #include "media/fuchsia/common/stream_processor_helper.h"
 #include "media/fuchsia/common/sysmem_buffer_pool.h"
@@ -39,6 +40,8 @@
 
   SysmemBufferWriterQueue input_writer_queue_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
  private:
   void OnInputBufferPoolCreated(std::unique_ptr<SysmemBufferPool> pool);
   void OnWriterCreated(std::unique_ptr<SysmemBufferWriter> writer);
diff --git a/media/fuchsia/common/stream_processor_helper.cc b/media/fuchsia/common/stream_processor_helper.cc
index 8465538..a741580 100644
--- a/media/fuchsia/common/stream_processor_helper.cc
+++ b/media/fuchsia/common/stream_processor_helper.cc
@@ -84,9 +84,12 @@
   processor_->EnableOnStreamFailed();
 }
 
-StreamProcessorHelper::~StreamProcessorHelper() = default;
+StreamProcessorHelper::~StreamProcessorHelper() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
 
 void StreamProcessorHelper::Process(IoPacket input) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(processor_);
 
   fuchsia::media::Packet packet;
@@ -113,6 +116,7 @@
 }
 
 void StreamProcessorHelper::ProcessEos() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(processor_);
 
   active_stream_ = true;
@@ -121,6 +125,8 @@
 }
 
 void StreamProcessorHelper::Reset() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   if (!active_stream_) {
     // Nothing to do if we don't have an active stream.
     return;
@@ -138,6 +144,8 @@
 
 void StreamProcessorHelper::OnStreamFailed(uint64_t stream_lifetime_ordinal,
                                            fuchsia::media::StreamError error) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   if (stream_lifetime_ordinal_ != stream_lifetime_ordinal) {
     return;
   }
@@ -155,6 +163,8 @@
 
 void StreamProcessorHelper::OnInputConstraints(
     fuchsia::media::StreamBufferConstraints constraints) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   // Buffer lifetime ordinal is an odd number incremented by 2 for each buffer
   // generation as required by StreamProcessor.
   input_buffer_lifetime_ordinal_ += 2;
@@ -178,6 +188,8 @@
 
 void StreamProcessorHelper::OnFreeInputPacket(
     fuchsia::media::PacketHeader free_input_packet) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   if (!free_input_packet.has_buffer_lifetime_ordinal() ||
       !free_input_packet.has_packet_index()) {
     DLOG(ERROR) << "Received OnFreeInputPacket() with missing required fields.";
@@ -206,6 +218,8 @@
 
 void StreamProcessorHelper::OnOutputConstraints(
     fuchsia::media::StreamOutputConstraints output_constraints) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   if (!output_constraints.has_stream_lifetime_ordinal()) {
     DLOG(ERROR)
         << "Received OnOutputConstraints() with missing required fields.";
@@ -242,6 +256,8 @@
 
 void StreamProcessorHelper::OnOutputFormat(
     fuchsia::media::StreamOutputFormat output_format) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   if (!output_format.has_stream_lifetime_ordinal() ||
       !output_format.has_format_details()) {
     DLOG(ERROR) << "Received OnOutputFormat() with missing required fields.";
@@ -259,6 +275,8 @@
 void StreamProcessorHelper::OnOutputPacket(fuchsia::media::Packet output_packet,
                                            bool error_detected_before,
                                            bool error_detected_during) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   if (!output_packet.has_header() ||
       !output_packet.header().has_buffer_lifetime_ordinal() ||
       !output_packet.header().has_packet_index() ||
@@ -299,6 +317,8 @@
 void StreamProcessorHelper::OnOutputEndOfStream(
     uint64_t stream_lifetime_ordinal,
     bool error_detected_before) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   if (stream_lifetime_ordinal != stream_lifetime_ordinal_) {
     return;
   }
@@ -316,6 +336,7 @@
 
 void StreamProcessorHelper::CompleteInputBuffersAllocation(
     fuchsia::sysmem::BufferCollectionTokenPtr sysmem_token) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!input_buffer_constraints_.IsEmpty());
   fuchsia::media::StreamBufferPartialSettings settings;
   settings.set_buffer_lifetime_ordinal(input_buffer_lifetime_ordinal_);
@@ -334,6 +355,7 @@
     size_t num_buffers_for_client,
     size_t num_buffers_for_server,
     fuchsia::sysmem::BufferCollectionTokenPtr collection_token) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!output_buffer_constraints_.IsEmpty());
   DCHECK_LE(num_buffers_for_client,
             output_buffer_constraints_.packet_count_for_client_max());
@@ -354,6 +376,8 @@
 void StreamProcessorHelper::OnRecycleOutputBuffer(
     uint64_t buffer_lifetime_ordinal,
     uint32_t packet_index) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   if (!processor_)
     return;
 
diff --git a/media/fuchsia/common/stream_processor_helper.h b/media/fuchsia/common/stream_processor_helper.h
index 87411f2..ed084c32 100644
--- a/media/fuchsia/common/stream_processor_helper.h
+++ b/media/fuchsia/common/stream_processor_helper.h
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 
 namespace media {
@@ -169,6 +170,9 @@
   fuchsia::media::StreamProcessorPtr processor_;
   Client* const client_;
 
+  // FIDL interfaces are thread-affine (see crbug.com/1012875).
+  THREAD_CHECKER(thread_checker_);
+
   base::WeakPtr<StreamProcessorHelper> weak_this_;
   base::WeakPtrFactory<StreamProcessorHelper> weak_factory_;
 
diff --git a/media/fuchsia/common/sysmem_buffer_pool.cc b/media/fuchsia/common/sysmem_buffer_pool.cc
index 94b674a..6c30ad8 100644
--- a/media/fuchsia/common/sysmem_buffer_pool.cc
+++ b/media/fuchsia/common/sysmem_buffer_pool.cc
@@ -31,11 +31,14 @@
       });
 }
 
-SysmemBufferPool::Creator::~Creator() = default;
+SysmemBufferPool::Creator::~Creator() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
 
 void SysmemBufferPool::Creator::Create(
     fuchsia::sysmem::BufferCollectionConstraints constraints,
     CreateCB create_cb) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!create_cb_);
   create_cb_ = std::move(create_cb);
   // BufferCollection needs to be synchronized to ensure that all token
@@ -64,11 +67,13 @@
 }
 
 SysmemBufferPool::~SysmemBufferPool() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (collection_)
     collection_->Close();
 }
 
 fuchsia::sysmem::BufferCollectionTokenPtr SysmemBufferPool::TakeToken() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!shared_tokens_.empty());
   auto token = std::move(shared_tokens_.back());
   shared_tokens_.pop_back();
@@ -76,6 +81,7 @@
 }
 
 void SysmemBufferPool::CreateReader(CreateReaderCB create_cb) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!create_reader_cb_);
   create_reader_cb_ = std::move(create_cb);
   collection_->WaitForBuffersAllocated(
@@ -83,6 +89,7 @@
 }
 
 void SysmemBufferPool::CreateWriter(CreateWriterCB create_cb) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!create_writer_cb_);
   create_writer_cb_ = std::move(create_cb);
   collection_->WaitForBuffersAllocated(
@@ -92,6 +99,8 @@
 void SysmemBufferPool::OnBuffersAllocated(
     zx_status_t status,
     fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   if (status != ZX_OK) {
     ZX_LOG(ERROR, status) << "Fail to allocate sysmem buffers.";
     OnError();
@@ -108,6 +117,7 @@
 }
 
 void SysmemBufferPool::OnError() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   collection_.Unbind();
   if (create_reader_cb_)
     std::move(create_reader_cb_).Run(nullptr);
@@ -132,6 +142,8 @@
 
 std::unique_ptr<SysmemBufferPool::Creator>
 BufferAllocator::MakeBufferPoolCreator(size_t num_of_tokens) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
   // Create a new sysmem buffer collection token for the allocated buffers.
   fuchsia::sysmem::BufferCollectionTokenPtr collection_token;
   allocator_->AllocateSharedCollection(collection_token.NewRequest());
diff --git a/media/fuchsia/common/sysmem_buffer_pool.h b/media/fuchsia/common/sysmem_buffer_pool.h
index a3fcf74..c4c6ceab 100644
--- a/media/fuchsia/common/sysmem_buffer_pool.h
+++ b/media/fuchsia/common/sysmem_buffer_pool.h
@@ -15,6 +15,7 @@
 #include "base/callback.h"
 #include "base/containers/span.h"
 #include "base/macros.h"
+#include "base/threading/thread_checker.h"
 
 namespace media {
 
@@ -50,6 +51,8 @@
     std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens_;
     CreateCB create_cb_;
 
+    THREAD_CHECKER(thread_checker_);
+
     DISALLOW_COPY_AND_ASSIGN(Creator);
   };
 
@@ -83,6 +86,9 @@
   CreateReaderCB create_reader_cb_;
   CreateWriterCB create_writer_cb_;
 
+  // FIDL interfaces are thread-affine (see crbug.com/1012875).
+  THREAD_CHECKER(thread_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(SysmemBufferPool);
 };
 
@@ -102,6 +108,8 @@
  private:
   fuchsia::sysmem::AllocatorPtr allocator_;
 
+  THREAD_CHECKER(thread_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(BufferAllocator);
 };
 
diff --git a/media/fuchsia/common/sysmem_buffer_writer_queue.cc b/media/fuchsia/common/sysmem_buffer_writer_queue.cc
index 1b8d11c6..79a75eff6 100644
--- a/media/fuchsia/common/sysmem_buffer_writer_queue.cc
+++ b/media/fuchsia/common/sysmem_buffer_writer_queue.cc
@@ -47,6 +47,7 @@
 
 void SysmemBufferWriterQueue::EnqueueBuffer(
     scoped_refptr<DecoderBuffer> buffer) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   pending_buffers_.push_back(PendingBuffer(buffer));
   PumpPackets();
 }
@@ -54,6 +55,7 @@
 void SysmemBufferWriterQueue::Start(std::unique_ptr<SysmemBufferWriter> writer,
                                     SendPacketCB send_packet_cb,
                                     EndOfStreamCB end_of_stream_cb) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(!writer_);
 
   writer_ = std::move(writer);
@@ -64,6 +66,7 @@
 }
 
 void SysmemBufferWriterQueue::PumpPackets() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   auto weak_this = weak_factory_.GetWeakPtr();
 
   while (writer_ && !is_paused_ &&
@@ -112,18 +115,21 @@
 }
 
 void SysmemBufferWriterQueue::ResetQueue() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   pending_buffers_.clear();
   input_queue_position_ = 0;
   is_paused_ = false;
 }
 
 void SysmemBufferWriterQueue::ResetBuffers() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   writer_.reset();
   send_packet_cb_ = SendPacketCB();
   end_of_stream_cb_ = EndOfStreamCB();
 }
 
 void SysmemBufferWriterQueue::ResetPositionAndPause() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   for (auto& buffer : pending_buffers_) {
     buffer.buffer_pos = 0;
     buffer.is_complete = false;
@@ -133,12 +139,14 @@
 }
 
 void SysmemBufferWriterQueue::Unpause() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(is_paused_);
   is_paused_ = false;
   PumpPackets();
 }
 
 void SysmemBufferWriterQueue::ReleaseBuffer(size_t buffer_index) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(writer_);
 
   // Mark the input buffer as complete.
@@ -164,6 +172,7 @@
 }
 
 size_t SysmemBufferWriterQueue::num_buffers() const {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return writer_ ? writer_->num_buffers() : 0;
 }
 
diff --git a/media/fuchsia/common/sysmem_buffer_writer_queue.h b/media/fuchsia/common/sysmem_buffer_writer_queue.h
index 61a3f86..b3d7d0e 100644
--- a/media/fuchsia/common/sysmem_buffer_writer_queue.h
+++ b/media/fuchsia/common/sysmem_buffer_writer_queue.h
@@ -13,6 +13,7 @@
 #include "base/containers/span.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/threading/thread_checker.h"
 #include "media/fuchsia/common/stream_processor_helper.h"
 #include "media/fuchsia/common/sysmem_buffer_writer.h"
 
@@ -94,6 +95,9 @@
   SendPacketCB send_packet_cb_;
   EndOfStreamCB end_of_stream_cb_;
 
+  // FIDL interfaces are thread-affine (see crbug.com/1012875).
+  THREAD_CHECKER(thread_checker_);
+
   base::WeakPtrFactory<SysmemBufferWriterQueue> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SysmemBufferWriterQueue);
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 827ff515..ba1b90e 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -351,6 +351,7 @@
       ":common",
       "//base",
       "//media",
+      "//media/gpu/chromeos:fourcc",
       "//ui/gfx/geometry",
     ]
   }
@@ -657,6 +658,7 @@
       "test:render_helpers",
       "//base/test:test_support",
       "//media:test_support",
+      "//media/gpu/chromeos:fourcc",
       "//mojo/core/embedder",
       "//testing/gtest",
     ]
diff --git a/media/gpu/image_processor.cc b/media/gpu/image_processor.cc
index 7908801..f0fffac 100644
--- a/media/gpu/image_processor.cc
+++ b/media/gpu/image_processor.cc
@@ -4,40 +4,69 @@
 
 #include "media/gpu/image_processor.h"
 
+#include <ostream>
+#include <sstream>
+
+#include "base/strings/stringprintf.h"
 #include "media/base/bind_to_current_loop.h"
+#include "media/base/video_frame.h"
 
 namespace media {
 
-ImageProcessor::PortConfig::PortConfig(
-    const VideoFrameLayout& layout,
-    const gfx::Size& visible_size,
-    const std::vector<VideoFrame::StorageType>& preferred_storage_types)
-    : PortConfig(layout,
-                 kUnassignedFourCC,
-                 visible_size,
-                 preferred_storage_types) {}
+namespace {
+
+std::ostream& operator<<(std::ostream& ostream,
+                         const VideoFrame::StorageType& storage_type) {
+  ostream << VideoFrame::StorageTypeToString(storage_type);
+  return ostream;
+}
+
+template <class T>
+std::string VectorToString(const std::vector<T>& vec) {
+  std::ostringstream result;
+  std::string delim;
+  result << "[";
+  for (const T& v : vec) {
+    result << delim << v;
+    if (delim.size() == 0)
+      delim = ", ";
+  }
+  result << "]";
+  return result.str();
+}
+
+}  // namespace
+
+ImageProcessor::PortConfig::PortConfig(const PortConfig&) = default;
 
 ImageProcessor::PortConfig::PortConfig(
-    const VideoFrameLayout& layout,
-    uint32_t fourcc,
+    Fourcc fourcc,
+    const gfx::Size& size,
+    const std::vector<ColorPlaneLayout>& planes,
     const gfx::Size& visible_size,
     const std::vector<VideoFrame::StorageType>& preferred_storage_types)
-    : layout(layout),
-      fourcc(fourcc),
+    : fourcc(fourcc),
+      size(size),
+      planes(planes),
       visible_size(visible_size),
       preferred_storage_types(preferred_storage_types) {}
 
-ImageProcessor::PortConfig::~PortConfig() {}
+ImageProcessor::PortConfig::~PortConfig() = default;
 
-ImageProcessor::ImageProcessor(const VideoFrameLayout& input_layout,
-                               VideoFrame::StorageType input_storage_type,
-                               const VideoFrameLayout& output_layout,
-                               VideoFrame::StorageType output_storage_type,
+std::string ImageProcessor::PortConfig::ToString() const {
+  return base::StringPrintf(
+      "PortConfig(format:%s, size:%s, planes: %s, visible_size:%s, "
+      "storage_types:%s)",
+      fourcc.ToString().c_str(), size.ToString().c_str(),
+      VectorToString(planes).c_str(), visible_size.ToString().c_str(),
+      VectorToString(preferred_storage_types).c_str());
+}
+
+ImageProcessor::ImageProcessor(const ImageProcessor::PortConfig& input_config,
+                               const ImageProcessor::PortConfig& output_config,
                                OutputMode output_mode)
-    : input_layout_(input_layout),
-      input_storage_type_(input_storage_type),
-      output_layout_(output_layout),
-      output_storage_type_(output_storage_type),
+    : input_config_(input_config),
+      output_config_(output_config),
       output_mode_(output_mode) {}
 
 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
diff --git a/media/gpu/image_processor.h b/media/gpu/image_processor.h
index 771652a..b57991e 100644
--- a/media/gpu/image_processor.h
+++ b/media/gpu/image_processor.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include <string>
 #include <vector>
 
 #include "base/callback_forward.h"
@@ -14,8 +15,9 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "build/build_config.h"
+#include "media/base/color_plane_layout.h"
 #include "media/base/video_frame.h"
-#include "media/base/video_frame_layout.h"
+#include "media/gpu/chromeos/fourcc.h"
 #include "media/gpu/media_gpu_export.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -48,27 +50,43 @@
   };
 
   // Encapsulates ImageProcessor input / output configurations.
-  // Note that |fourcc| is used when format cannot be described in |layout|,
-  // e.g. platform specific format not listed in VideoPixelFormat. The default
-  // value of |fourcc| is kUnassignedFourCC.
   struct MEDIA_GPU_EXPORT PortConfig {
     PortConfig() = delete;
+    PortConfig(const PortConfig&);
     PortConfig(
-        const VideoFrameLayout& layout,
-        const gfx::Size& visible_size,
-        const std::vector<VideoFrame::StorageType>& preferred_storage_types);
-    PortConfig(
-        const VideoFrameLayout& layout,
-        uint32_t fourcc,
+        Fourcc fourcc,
+        const gfx::Size& size,
+        const std::vector<ColorPlaneLayout>& planes,
         const gfx::Size& visible_size,
         const std::vector<VideoFrame::StorageType>& preferred_storage_types);
     ~PortConfig();
 
-    static const uint32_t kUnassignedFourCC = 0u;
+    // Get the first |preferred_storage_types|.
+    // If |preferred_storage_types| is empty, return STORAGE_UNKNOWN.
+    VideoFrame::StorageType storage_type() const {
+      return preferred_storage_types.empty() ? VideoFrame::STORAGE_UNKNOWN
+                                             : preferred_storage_types.front();
+    }
 
-    const VideoFrameLayout layout;
-    const uint32_t fourcc;
+    // Output human readable string of PortConfig.
+    // Example:
+    // PortConfig(format::NV12, size:640x480, planes:[(640, 0, 307200),
+    // (640,0,153600)], visible_size:640x480, storage_types:[DMABUFS])
+    std::string ToString() const;
+
+    // Video frame format represented as fourcc type.
+    const Fourcc fourcc;
+
+    // Width and height of the video frame in pixels. This must include pixel
+    // data for the whole image; i.e. for YUV formats with subsampled chroma
+    // planes. If a visible portion of the image does not line up on a sample
+    // boundary, |size_| must be rounded up appropriately.
+    const gfx::Size size;
+
+    // Layout property (stride, offset, size of bytes) for each color plane.
+    const std::vector<ColorPlaneLayout> planes;
     const gfx::Size visible_size;
+    // List of preferred storage types.
     const std::vector<VideoFrame::StorageType> preferred_storage_types;
   };
 
@@ -95,21 +113,8 @@
 
   virtual ~ImageProcessor() = default;
 
-  // Returns input layout of the processor.
-  const VideoFrameLayout& input_layout() const { return input_layout_; }
-
-  // Returns output layout of the processor.
-  const VideoFrameLayout& output_layout() const { return output_layout_; }
-
-  // Returns input storage type.
-  VideoFrame::StorageType input_storage_type() const {
-    return input_storage_type_;
-  }
-
-  // Returns output storage type.
-  VideoFrame::StorageType output_storage_type() const {
-    return output_storage_type_;
-  }
+  const PortConfig& input_config() const { return input_config_; }
+  const PortConfig& output_config() const { return output_config_; }
 
   // Returns output mode.
   // TODO(crbug.com/907767): Remove it once ImageProcessor always works as
@@ -149,21 +154,15 @@
   virtual bool Reset() = 0;
 
  protected:
-  ImageProcessor(const VideoFrameLayout& input_layout,
-                 VideoFrame::StorageType input_storage_type,
-                 const VideoFrameLayout& output_layout,
-                 VideoFrame::StorageType output_storage_type,
+  ImageProcessor(const PortConfig& input_config,
+                 const PortConfig& output_config,
                  OutputMode output_mode);
 
-  // Stores input frame's layout and storage type.
-  const VideoFrameLayout input_layout_;
-  const VideoFrame::StorageType input_storage_type_;
+  const PortConfig input_config_;
+  const PortConfig output_config_;
 
-  // Stores output frame's layout, storage type and output mode.
   // TODO(crbug.com/907767): Remove |output_mode_| once ImageProcessor always
   // works as IMPORT mode for output.
-  const VideoFrameLayout output_layout_;
-  const VideoFrame::StorageType output_storage_type_;
   const OutputMode output_mode_;
 
  private:
diff --git a/media/gpu/image_processor_test.cc b/media/gpu/image_processor_test.cc
index 8b0833de..d653e49 100644
--- a/media/gpu/image_processor_test.cc
+++ b/media/gpu/image_processor_test.cc
@@ -15,6 +15,7 @@
 #include "media/base/video_frame.h"
 #include "media/base/video_frame_layout.h"
 #include "media/base/video_types.h"
+#include "media/gpu/chromeos/fourcc.h"
 #include "media/gpu/image_processor.h"
 #include "media/gpu/test/image.h"
 #include "media/gpu/test/image_processor/image_processor_client.h"
@@ -84,18 +85,16 @@
       const std::vector<VideoFrame::StorageType>& input_storage_types,
       const test::Image& output_image,
       const std::vector<VideoFrame::StorageType>& output_storage_types) {
-    const VideoPixelFormat input_format = input_image.PixelFormat();
-    const VideoPixelFormat output_format = output_image.PixelFormat();
-    auto input_config_layout =
-        test::CreateVideoFrameLayout(input_format, input_image.Size());
-    auto output_config_layout =
-        test::CreateVideoFrameLayout(output_format, output_image.Size());
-    LOG_ASSERT(input_config_layout);
-    LOG_ASSERT(output_config_layout);
-    ImageProcessor::PortConfig input_config(
-        *input_config_layout, input_image.Size(), input_storage_types);
-    ImageProcessor::PortConfig output_config(
-        *output_config_layout, output_image.Size(), output_storage_types);
+    Fourcc input_fourcc =
+        Fourcc::FromVideoPixelFormat(input_image.PixelFormat());
+    Fourcc output_fourcc =
+        Fourcc::FromVideoPixelFormat(output_image.PixelFormat());
+    ImageProcessor::PortConfig input_config(input_fourcc, input_image.Size(),
+                                            {}, input_image.Size(),
+                                            input_storage_types);
+    ImageProcessor::PortConfig output_config(output_fourcc, output_image.Size(),
+                                             {}, output_image.Size(),
+                                             output_storage_types);
     // TODO(crbug.com/917951): Select more appropriate number of buffers.
     constexpr size_t kNumBuffers = 1;
     LOG_ASSERT(output_image.IsMetadataLoaded());
@@ -104,7 +103,8 @@
     // TODO(crbug.com/917951): We should validate a scaled image with SSIM.
     // Validating processed frames is currently not supported when a format is
     // not YUV or when scaling images.
-    if (IsYuvPlanar(input_format) && IsYuvPlanar(output_format) &&
+    if (IsYuvPlanar(input_fourcc.ToVideoPixelFormat()) &&
+        IsYuvPlanar(output_fourcc.ToVideoPixelFormat()) &&
         input_image.Size() == output_image.Size()) {
       auto vf_validator = test::VideoFrameValidator::Create(
           {output_image.Checksum()}, output_image.PixelFormat());
@@ -116,7 +116,7 @@
           base::FilePath(base::FilePath::kCurrentDirectory)
               .Append(g_env->GetTestOutputFilePath());
       test::VideoFrameFileWriter::OutputFormat saved_file_format =
-          IsYuvPlanar(output_format)
+          IsYuvPlanar(output_fourcc.ToVideoPixelFormat())
               ? test::VideoFrameFileWriter::OutputFormat::kYUV
               : test::VideoFrameFileWriter::OutputFormat::kPNG;
       frame_processors.push_back(
diff --git a/media/gpu/libyuv_image_processor.cc b/media/gpu/libyuv_image_processor.cc
index 68d148ec..9bd914d 100644
--- a/media/gpu/libyuv_image_processor.cc
+++ b/media/gpu/libyuv_image_processor.cc
@@ -8,6 +8,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "media/base/bind_to_current_loop.h"
+#include "media/gpu/chromeos/fourcc.h"
 #include "media/gpu/macros.h"
 #include "media/gpu/video_frame_mapper.h"
 #include "media/gpu/video_frame_mapper_factory.h"
@@ -25,25 +26,21 @@
   Unsupported,
 };
 
-SupportResult IsFormatSupported(VideoPixelFormat input_format,
-                                VideoPixelFormat output_format) {
-  constexpr struct {
-    VideoPixelFormat input;
-    VideoPixelFormat output;
+SupportResult IsFormatSupported(Fourcc input_fourcc, Fourcc output_fourcc) {
+  static constexpr struct {
+    uint32_t input;
+    uint32_t output;
     bool need_pivot;
   } kSupportFormatConversionArray[] = {
-      {PIXEL_FORMAT_ARGB, PIXEL_FORMAT_NV12, false},
-      {PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12, false},
-      {PIXEL_FORMAT_YV12, PIXEL_FORMAT_NV12, false},
-      {PIXEL_FORMAT_ABGR, PIXEL_FORMAT_NV12, true},
-      {PIXEL_FORMAT_XBGR, PIXEL_FORMAT_NV12, true},
+      {Fourcc::AR24, Fourcc::NV12, false}, {Fourcc::YU12, Fourcc::NV12, false},
+      {Fourcc::YV12, Fourcc::NV12, false}, {Fourcc::AB24, Fourcc::NV12, true},
+      {Fourcc::XB24, Fourcc::NV12, true},
   };
 
-  for (auto* conv = std::cbegin(kSupportFormatConversionArray);
-       conv != std::cend(kSupportFormatConversionArray); conv++) {
-    if (conv->input == input_format && conv->output == output_format) {
-      return conv->need_pivot ? SupportResult::SupportedWithPivot
-                              : SupportResult::Supported;
+  for (const auto& conv : kSupportFormatConversionArray) {
+    if (conv.input == input_fourcc && conv.output == output_fourcc) {
+      return conv.need_pivot ? SupportResult::SupportedWithPivot
+                             : SupportResult::Supported;
     }
   }
 
@@ -53,21 +50,11 @@
 }  // namespace
 
 LibYUVImageProcessor::LibYUVImageProcessor(
-    const VideoFrameLayout& input_layout,
-    const gfx::Size& input_visible_size,
-    VideoFrame::StorageType input_storage_type,
-    const VideoFrameLayout& output_layout,
-    const gfx::Size& output_visible_size,
-    VideoFrame::StorageType output_storage_type,
+    const ImageProcessor::PortConfig& input_config,
+    const ImageProcessor::PortConfig& output_config,
     std::unique_ptr<VideoFrameMapper> video_frame_mapper,
     ErrorCB error_cb)
-    : ImageProcessor(input_layout,
-                     input_storage_type,
-                     output_layout,
-                     output_storage_type,
-                     OutputMode::IMPORT),
-      input_visible_rect_(input_visible_size),
-      output_visible_rect_(output_visible_size),
+    : ImageProcessor(input_config, output_config, OutputMode::IMPORT),
       video_frame_mapper_(std::move(video_frame_mapper)),
       error_cb_(error_cb),
       process_thread_("LibYUVImageProcessorThread") {}
@@ -83,7 +70,7 @@
 std::unique_ptr<LibYUVImageProcessor> LibYUVImageProcessor::Create(
     const ImageProcessor::PortConfig& input_config,
     const ImageProcessor::PortConfig& output_config,
-    const ImageProcessor::OutputMode output_mode,
+    ImageProcessor::OutputMode output_mode,
     ErrorCB error_cb) {
   VLOGF(2);
 
@@ -94,7 +81,7 @@
 #if defined(OS_LINUX)
     if (input_type == VideoFrame::STORAGE_DMABUFS) {
       video_frame_mapper = VideoFrameMapperFactory::CreateMapper(
-          input_config.layout.format(), true);
+          input_config.fourcc.ToVideoPixelFormat(), true);
       if (video_frame_mapper) {
         input_storage_type = input_type;
         break;
@@ -130,17 +117,21 @@
     return nullptr;
   }
 
-  SupportResult res = IsFormatSupported(input_config.layout.format(),
-                                        output_config.layout.format());
+  SupportResult res =
+      IsFormatSupported(input_config.fourcc, output_config.fourcc);
   if (res == SupportResult::Unsupported) {
-    VLOGF(2) << "Conversion from " << input_config.layout.format() << " to "
-             << output_config.layout.format() << " is not supported";
+    VLOGF(2) << "Conversion from " << input_config.fourcc.ToString() << " to "
+             << output_config.fourcc.ToString() << " is not supported";
     return nullptr;
   }
 
   auto processor = base::WrapUnique(new LibYUVImageProcessor(
-      input_config.layout, input_config.visible_size, input_storage_type,
-      output_config.layout, output_config.visible_size, output_storage_type,
+      ImageProcessor::PortConfig(input_config.fourcc, input_config.size, {},
+                                 input_config.visible_size,
+                                 {input_storage_type}),
+      ImageProcessor::PortConfig(output_config.fourcc, output_config.size, {},
+                                 output_config.visible_size,
+                                 {output_storage_type}),
       std::move(video_frame_mapper),
       media::BindToCurrentLoop(std::move(error_cb))));
   if (res == SupportResult::SupportedWithPivot) {
@@ -160,7 +151,7 @@
   }
 
   VLOGF(2) << "LibYUVImageProcessor created for converting from "
-           << input_config.layout << " to " << output_config.layout;
+           << input_config.ToString() << " to " << output_config.ToString();
   return processor;
 }
 
@@ -170,11 +161,13 @@
     FrameReadyCB cb) {
   DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
   DVLOGF(4);
-  DCHECK_EQ(input_frame->layout().format(), input_layout_.format());
-  DCHECK(input_frame->layout().coded_size() == input_layout_.coded_size());
-  DCHECK_EQ(output_frame->layout().format(), output_layout_.format());
-  DCHECK(output_frame->layout().coded_size() == output_layout_.coded_size());
-  DCHECK(input_storage_type_ == input_frame->storage_type() ||
+  DCHECK_EQ(input_frame->layout().format(),
+            input_config_.fourcc.ToVideoPixelFormat());
+  DCHECK(input_frame->layout().coded_size() == input_config_.size);
+  DCHECK_EQ(output_frame->layout().format(),
+            output_config_.fourcc.ToVideoPixelFormat());
+  DCHECK(output_frame->layout().coded_size() == output_config_.size);
+  DCHECK(input_config_.storage_type() == input_frame->storage_type() ||
          VideoFrame::IsStorageTypeMappable(input_frame->storage_type()));
   DCHECK(VideoFrame::IsStorageTypeMappable(output_frame->storage_type()));
 
diff --git a/media/gpu/libyuv_image_processor.h b/media/gpu/libyuv_image_processor.h
index aaf5131..66e44f1 100644
--- a/media/gpu/libyuv_image_processor.h
+++ b/media/gpu/libyuv_image_processor.h
@@ -45,16 +45,12 @@
   static std::unique_ptr<LibYUVImageProcessor> Create(
       const ImageProcessor::PortConfig& input_config,
       const ImageProcessor::PortConfig& output_config,
-      const ImageProcessor::OutputMode output_mode,
+      ImageProcessor::OutputMode output_mode,
       ErrorCB error_cb);
 
  private:
-  LibYUVImageProcessor(const VideoFrameLayout& input_layout,
-                       const gfx::Size& input_visible_size,
-                       VideoFrame::StorageType input_storage_type,
-                       const VideoFrameLayout& output_layout,
-                       const gfx::Size& output_visible_size,
-                       VideoFrame::StorageType output_storage_type,
+  LibYUVImageProcessor(const ImageProcessor::PortConfig& input_config,
+                       const ImageProcessor::PortConfig& output_config,
                        std::unique_ptr<VideoFrameMapper> video_frame_mapper,
                        ErrorCB error_cb);
 
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.cc b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
index b440d54..cc94430 100644
--- a/media/gpu/mac/vt_video_decode_accelerator_mac.cc
+++ b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
@@ -650,7 +650,7 @@
   nalu_data_sizes.reserve(3);
   nalu_data_ptrs.push_back(&active_sps_.front());
   nalu_data_sizes.push_back(active_sps_.size());
-  if (!last_spsext_.empty()) {
+  if (!active_spsext_.empty()) {
     nalu_data_ptrs.push_back(&active_spsext_.front());
     nalu_data_sizes.push_back(active_spsext_.size());
   }
@@ -773,8 +773,9 @@
       return;
     }
     switch (nalu.nal_unit_type) {
-      case H264NALU::kSPS:
-        result = parser_.ParseSPS(&last_sps_id_);
+      case H264NALU::kSPS: {
+        int sps_id = -1;
+        result = parser_.ParseSPS(&sps_id);
         if (result == H264Parser::kUnsupportedStream) {
           WriteToMediaLog(MediaLog::MEDIALOG_ERROR, "Unsupported SPS");
           NotifyError(PLATFORM_FAILURE, SFT_UNSUPPORTED_STREAM);
@@ -785,16 +786,27 @@
           NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM);
           return;
         }
-        last_sps_.assign(nalu.data, nalu.data + nalu.size);
-        last_spsext_.clear();
+        seen_sps_[sps_id].assign(nalu.data, nalu.data + nalu.size);
+        seen_spsext_.erase(sps_id);
         break;
+      }
 
-      case H264NALU::kSPSExt:
-        last_spsext_.assign(nalu.data, nalu.data + nalu.size);
+      case H264NALU::kSPSExt: {
+        int sps_id = -1;
+        result = parser_.ParseSPSExt(&sps_id);
+        if (result != H264Parser::kOk) {
+          WriteToMediaLog(MediaLog::MEDIALOG_ERROR,
+                          "Could not parse SPS extension");
+          NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM);
+          return;
+        }
+        seen_spsext_[sps_id].assign(nalu.data, nalu.data + nalu.size);
         break;
+      }
 
-      case H264NALU::kPPS:
-        result = parser_.ParsePPS(&last_pps_id_);
+      case H264NALU::kPPS: {
+        int pps_id = -1;
+        result = parser_.ParsePPS(&pps_id);
         if (result == H264Parser::kUnsupportedStream) {
           WriteToMediaLog(MediaLog::MEDIALOG_ERROR, "Unsupported PPS");
           NotifyError(PLATFORM_FAILURE, SFT_UNSUPPORTED_STREAM);
@@ -805,8 +817,9 @@
           NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM);
           return;
         }
-        last_pps_.assign(nalu.data, nalu.data + nalu.size);
+        seen_pps_[pps_id].assign(nalu.data, nalu.data + nalu.size);
         break;
+      }
 
       case H264NALU::kSliceDataA:
       case H264NALU::kSliceDataB:
@@ -833,7 +846,6 @@
           }
 
           // Lookup SPS and PPS.
-          DCHECK_EQ(slice_hdr.pic_parameter_set_id, last_pps_id_);
           const H264PPS* pps = parser_.GetPPS(slice_hdr.pic_parameter_set_id);
           if (!pps) {
             WriteToMediaLog(MediaLog::MEDIALOG_ERROR,
@@ -842,7 +854,6 @@
             return;
           }
 
-          DCHECK_EQ(pps->seq_parameter_set_id, last_sps_id_);
           const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
           if (!sps) {
             WriteToMediaLog(MediaLog::MEDIALOG_ERROR,
@@ -852,11 +863,12 @@
           }
 
           // Record the configuration.
-          // TODO(sandersd): Ideally this would be skipped if we know there
-          // have not been any parameter sets since the last frame.
-          active_sps_ = last_sps_;
-          active_spsext_ = last_spsext_;
-          active_pps_ = last_pps_;
+          DCHECK(seen_pps_.count(slice_hdr.pic_parameter_set_id));
+          DCHECK(seen_sps_.count(pps->seq_parameter_set_id));
+          active_sps_ = seen_sps_[slice_hdr.pic_parameter_set_id];
+          // Note: SPS extension lookup may create an empty entry.
+          active_spsext_ = seen_spsext_[slice_hdr.pic_parameter_set_id];
+          active_pps_ = seen_pps_[pps->seq_parameter_set_id];
 
           // Compute and store frame properties. |image_size| gets filled in
           // later, since it comes from the decoder configuration.
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.h b/media/gpu/mac/vt_video_decode_accelerator_mac.h
index 07ae070..1083d61 100644
--- a/media/gpu/mac/vt_video_decode_accelerator_mac.h
+++ b/media/gpu/mac/vt_video_decode_accelerator_mac.h
@@ -243,26 +243,23 @@
   base::ScopedCFTypeRef<VTDecompressionSessionRef> session_;
   H264Parser parser_;
 
-  // Last SPS and PPS seen in the bitstream.
-  //
-  // TODO(sandersd): Keep a map from ID to last SPS/PPS, for streams that
-  // maintain multiple active configurations. (I've never seen such a stream.)
-  int last_sps_id_ = -1;
-  int last_pps_id_ = -1;
-  std::vector<uint8_t> last_sps_;
-  std::vector<uint8_t> last_spsext_;
-  std::vector<uint8_t> last_pps_;
+  // SPSs and PPSs seen in the bitstream.
+  std::map<int, std::vector<uint8_t>> seen_sps_;
+  std::map<int, std::vector<uint8_t>> seen_spsext_;
+  std::map<int, std::vector<uint8_t>> seen_pps_;
 
-  // Last SPS and PPS referenced by a slice. In practice these will be the same
-  // as the last seen values, unless the bitstream is malformatted.
+  // SPS and PPS most recently activated by an IDR.
+  // TODO(sandersd): Enable configuring with multiple PPSs.
   std::vector<uint8_t> active_sps_;
   std::vector<uint8_t> active_spsext_;
   std::vector<uint8_t> active_pps_;
 
-  // Last SPS and PPS the decoder was confgured with.
+  // SPS and PPS the decoder is currently confgured with.
   std::vector<uint8_t> configured_sps_;
   std::vector<uint8_t> configured_spsext_;
   std::vector<uint8_t> configured_pps_;
+
+  // Visible rect the decoder is configured to use.
   gfx::Size configured_size_;
 
   bool waiting_for_idr_ = true;
diff --git a/media/gpu/test/BUILD.gn b/media/gpu/test/BUILD.gn
index 572693b..514aa17 100644
--- a/media/gpu/test/BUILD.gn
+++ b/media/gpu/test/BUILD.gn
@@ -157,21 +157,24 @@
   ]
 }
 
-static_library("image_processor") {
-  testonly = true
-  sources = [
-    "image_processor/image_processor_client.cc",
-    "image_processor/image_processor_client.h",
-  ]
-  deps = [
-    ":helpers",
-    ":render_helpers",
-    "//media:test_support",
-    "//media/gpu",
-    "//testing/gtest",
-    "//third_party/libyuv",
-  ]
-  data = [
-    "//media/test/data/",
-  ]
+if (use_vaapi || use_v4l2_codec) {
+  static_library("image_processor") {
+    testonly = true
+    sources = [
+      "image_processor/image_processor_client.cc",
+      "image_processor/image_processor_client.h",
+    ]
+    deps = [
+      ":helpers",
+      ":render_helpers",
+      "//media:test_support",
+      "//media/gpu",
+      "//media/gpu/chromeos:fourcc",
+      "//testing/gtest",
+      "//third_party/libyuv",
+    ]
+    data = [
+      "//media/test/data/",
+    ]
+  }
 }
diff --git a/media/gpu/test/image_processor/image_processor_client.cc b/media/gpu/test/image_processor/image_processor_client.cc
index 6de8fa2b..b4ca656 100644
--- a/media/gpu/test/image_processor/image_processor_client.cc
+++ b/media/gpu/test/image_processor/image_processor_client.cc
@@ -18,6 +18,7 @@
 #include "media/base/video_frame.h"
 #include "media/base/video_frame_layout.h"
 #include "media/gpu/buildflags.h"
+#include "media/gpu/chromeos/fourcc.h"
 #include "media/gpu/image_processor_factory.h"
 #include "media/gpu/test/image.h"
 #include "media/gpu/test/video_frame_helpers.h"
@@ -107,22 +108,45 @@
   done->Signal();
 }
 
+namespace {
+
+base::Optional<VideoFrameLayout> CreateLayout(
+    const ImageProcessor::PortConfig& config) {
+  // V4L2 specific format hack:
+  // If VDA's output format is V4L2_PIX_FMT_MT21C, which is a platform specific
+  // format and now is only used for MT8173 VDA output and its image processor
+  // input, we set VideoFrameLayout for image processor's input with format
+  // PIXEL_FORMAT_NV12 as NV12's layout is the same as MT21.
+  const VideoPixelFormat pixel_format = config.fourcc.ToVideoPixelFormat();
+  if (config.planes.size() <= 1) {
+    return VideoFrameLayout::Create(pixel_format, config.size);
+  }
+  return VideoFrameLayout::CreateMultiPlanar(pixel_format, config.size,
+                                             config.planes);
+}
+
+}  // namespace
+
 scoped_refptr<VideoFrame> ImageProcessorClient::CreateInputFrame(
     const Image& input_image) const {
   DCHECK_CALLED_ON_VALID_THREAD(test_main_thread_checker_);
   LOG_ASSERT(image_processor_);
   LOG_ASSERT(input_image.IsLoaded());
 
-  const auto& input_layout = image_processor_->input_layout();
-  if (VideoFrame::IsStorageTypeMappable(
-          image_processor_->input_storage_type())) {
+  const ImageProcessor::PortConfig& input_config =
+      image_processor_->input_config();
+  const VideoFrame::StorageType input_storage_type =
+      input_config.storage_type();
+  base::Optional<VideoFrameLayout> input_layout = CreateLayout(input_config);
+  LOG_ASSERT(input_layout);
+
+  if (VideoFrame::IsStorageTypeMappable(input_storage_type)) {
     return CloneVideoFrame(gpu_memory_buffer_factory_.get(),
                            CreateVideoFrameFromImage(input_image).get(),
-                           input_layout, VideoFrame::STORAGE_OWNED_MEMORY);
+                           *input_layout, VideoFrame::STORAGE_OWNED_MEMORY);
   } else {
 #if defined(OS_CHROMEOS)
-    LOG_ASSERT(image_processor_->input_storage_type() ==
-               VideoFrame::STORAGE_DMABUFS);
+    LOG_ASSERT(input_storage_type == VideoFrame::STORAGE_DMABUFS);
     // NV12 and YV12 are the only formats that can be allocated with
     // gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE. So
     // gfx::BufferUsage::GPU_READ_CPU_READ_WRITE is specified for RGB formats.
@@ -132,7 +156,7 @@
             : gfx::BufferUsage::GPU_READ_CPU_READ_WRITE;
     return CloneVideoFrame(gpu_memory_buffer_factory_.get(),
                            CreateVideoFrameFromImage(input_image).get(),
-                           input_layout, VideoFrame::STORAGE_DMABUFS,
+                           *input_layout, VideoFrame::STORAGE_DMABUFS,
                            dst_buffer_usage);
 #endif
     return nullptr;
@@ -145,19 +169,22 @@
   LOG_ASSERT(output_image.IsMetadataLoaded());
   LOG_ASSERT(image_processor_);
 
-  const auto& output_layout = image_processor_->output_layout();
-  if (VideoFrame::IsStorageTypeMappable(
-          image_processor_->output_storage_type())) {
+  const ImageProcessor::PortConfig& output_config =
+      image_processor_->output_config();
+  const VideoFrame::StorageType output_storage_type =
+      output_config.storage_type();
+  base::Optional<VideoFrameLayout> output_layout = CreateLayout(output_config);
+  LOG_ASSERT(output_layout);
+  if (VideoFrame::IsStorageTypeMappable(output_storage_type)) {
     return VideoFrame::CreateFrameWithLayout(
-        output_layout, gfx::Rect(output_image.Size()), output_image.Size(),
+        *output_layout, gfx::Rect(output_image.Size()), output_image.Size(),
         base::TimeDelta(), false /* zero_initialize_memory*/);
   } else {
 #if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
-    LOG_ASSERT(image_processor_->output_storage_type() ==
-               VideoFrame::STORAGE_DMABUFS);
+    LOG_ASSERT(output_storage_type == VideoFrame::STORAGE_DMABUFS);
     return CreatePlatformVideoFrame(
-        gpu_memory_buffer_factory_.get(), output_layout.format(),
-        output_layout.coded_size(), gfx::Rect(output_image.Size()),
+        gpu_memory_buffer_factory_.get(), output_layout->format(),
+        output_layout->coded_size(), gfx::Rect(output_image.Size()),
         output_image.Size(), base::TimeDelta(),
         gfx::BufferUsage::GPU_READ_CPU_READ_WRITE);
 #endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
diff --git a/media/gpu/test/video_player/test_vda_video_decoder.cc b/media/gpu/test/video_player/test_vda_video_decoder.cc
index d45aef8..5134e486 100644
--- a/media/gpu/test/video_player/test_vda_video_decoder.cc
+++ b/media/gpu/test/video_player/test_vda_video_decoder.cc
@@ -12,7 +12,6 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "media/base/bind_to_current_loop.h"
 #include "media/base/video_frame.h"
 #include "media/base/waiting.h"
 #include "media/gpu/gpu_video_decode_accelerator_factory.h"
@@ -47,12 +46,14 @@
       gpu_memory_buffer_factory_(gpu_memory_buffer_factory),
 #endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
       decode_start_timestamps_(kTimestampCacheSize) {
-  DETACH_FROM_SEQUENCE(vda_wrapper_sequence_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(vda_wrapper_sequence_checker_);
 
   // TODO(crbug.com/933632) Remove support for allocate mode, and always use
   // import mode. Support for allocate mode is temporary maintained for older
   // platforms that don't support import mode.
 
+  vda_wrapper_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+
   weak_this_ = weak_this_factory_.GetWeakPtr();
 }
 
@@ -268,6 +269,8 @@
 }
 
 void TestVDAVideoDecoder::DismissPictureBuffer(int32_t picture_buffer_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(vda_wrapper_sequence_checker_);
+
   // Drop reference to the video frame associated with the picture buffer, so
   // the video frame and related texture are automatically destroyed once the
   // renderer and video frame processors are done using them.
@@ -321,13 +324,24 @@
   // |video_frames_| to map between picture buffers and frames, but that
   // reference will be released when the decoder calls DismissPictureBuffer()
   // (e.g. on a resolution change).
-  base::OnceClosure reuse_cb = BindToCurrentLoop(
-      base::BindOnce(&TestVDAVideoDecoder::ReusePictureBufferTask, weak_this_,
-                     picture.picture_buffer_id()));
+  base::OnceClosure reuse_cb =
+      base::BindOnce(&TestVDAVideoDecoder::ReusePictureBufferThunk, weak_this_,
+                     vda_wrapper_task_runner_, picture.picture_buffer_id());
   wrapped_video_frame->AddDestructionObserver(std::move(reuse_cb));
   output_cb_.Run(std::move(wrapped_video_frame));
 }
 
+// static
+void TestVDAVideoDecoder::ReusePictureBufferThunk(
+    base::Optional<base::WeakPtr<TestVDAVideoDecoder>> vda_video_decoder,
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    int32_t picture_buffer_id) {
+  DCHECK(vda_video_decoder);
+  task_runner->PostTask(
+      FROM_HERE, base::BindOnce(&TestVDAVideoDecoder::ReusePictureBufferTask,
+                                *vda_video_decoder, picture_buffer_id));
+}
+
 // Called when a picture buffer is ready to be re-used.
 void TestVDAVideoDecoder::ReusePictureBufferTask(int32_t picture_buffer_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(vda_wrapper_sequence_checker_);
diff --git a/media/gpu/test/video_player/test_vda_video_decoder.h b/media/gpu/test/video_player/test_vda_video_decoder.h
index 244aed5..76adaf17 100644
--- a/media/gpu/test/video_player/test_vda_video_decoder.h
+++ b/media/gpu/test/video_player/test_vda_video_decoder.h
@@ -80,6 +80,12 @@
   void NotifyResetDone() override;
   void NotifyError(VideoDecodeAccelerator::Error error) override;
 
+  // Helper thunk to avoid dereferencing WeakPtrs on the wrong thread.
+  static void ReusePictureBufferThunk(
+      base::Optional<base::WeakPtr<TestVDAVideoDecoder>> decoder_client,
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
+      int32_t picture_buffer_id);
+
   // Get the next bitstream buffer id to be used.
   int32_t GetNextBitstreamBufferId();
   // Get the next picture buffer id to be used.
@@ -118,6 +124,8 @@
 
   std::unique_ptr<VideoDecodeAccelerator> decoder_;
 
+  scoped_refptr<base::SequencedTaskRunner> vda_wrapper_task_runner_;
+
   SEQUENCE_CHECKER(vda_wrapper_sequence_checker_);
 
   base::WeakPtr<TestVDAVideoDecoder> weak_this_;
diff --git a/media/gpu/test/video_player/video_decoder_client.cc b/media/gpu/test/video_player/video_decoder_client.cc
index bd796ad1..f323bd9e 100644
--- a/media/gpu/test/video_player/video_decoder_client.cc
+++ b/media/gpu/test/video_player/video_decoder_client.cc
@@ -11,7 +11,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "media/base/bind_to_current_loop.h"
 #include "media/base/waiting.h"
 #include "media/gpu/buildflags.h"
 #include "media/gpu/macros.h"
@@ -32,6 +31,21 @@
 namespace media {
 namespace test {
 
+namespace {
+// Callbacks can be called from any thread, but WeakPtrs are not thread-safe.
+// This helper thunk wraps a WeakPtr into an 'Optional' value, so the WeakPtr is
+// only dereferenced after rescheduling the task on the specified task runner.
+template <typename F, typename... Args>
+void CallbackThunk(
+    base::Optional<base::WeakPtr<VideoDecoderClient>> decoder_client,
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    F f,
+    Args... args) {
+  DCHECK(decoder_client);
+  task_runner->PostTask(FROM_HERE, base::BindOnce(f, *decoder_client, args...));
+}
+}  // namespace
+
 VideoDecoderClient::VideoDecoderClient(
     const VideoPlayer::EventCallback& event_cb,
     gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
@@ -208,10 +222,16 @@
       kNoTransformation, video_->Resolution(), gfx::Rect(video_->Resolution()),
       video_->Resolution(), std::vector<uint8_t>(0), EncryptionScheme());
 
-  VideoDecoder::InitCB init_cb = BindToCurrentLoop(
-      base::BindOnce(&VideoDecoderClient::DecoderInitializedTask, weak_this_));
-  VideoDecoder::OutputCB output_cb = BindToCurrentLoop(
-      base::BindRepeating(&VideoDecoderClient::FrameReadyTask, weak_this_));
+  VideoDecoder::InitCB init_cb = base::BindOnce(
+      CallbackThunk<decltype(&VideoDecoderClient::DecoderInitializedTask),
+                    bool>,
+      weak_this_, decoder_client_thread_.task_runner(),
+      &VideoDecoderClient::DecoderInitializedTask);
+  VideoDecoder::OutputCB output_cb = base::BindRepeating(
+      CallbackThunk<decltype(&VideoDecoderClient::FrameReadyTask),
+                    scoped_refptr<VideoFrame>>,
+      weak_this_, decoder_client_thread_.task_runner(),
+      &VideoDecoderClient::FrameReadyTask);
 
   decoder_->Initialize(config, false, nullptr, std::move(init_cb), output_cb,
                        WaitingCB());
@@ -283,8 +303,11 @@
       reinterpret_cast<const uint8_t*>(fragment_bytes.data()), fragment_size);
   bitstream_buffer->set_timestamp(base::TimeTicks::Now().since_origin());
 
-  VideoDecoder::DecodeCB decode_cb = BindToCurrentLoop(
-      base::BindOnce(&VideoDecoderClient::DecodeDoneTask, weak_this_));
+  VideoDecoder::DecodeCB decode_cb = base::BindOnce(
+      CallbackThunk<decltype(&VideoDecoderClient::DecodeDoneTask),
+                    media::DecodeStatus>,
+      weak_this_, decoder_client_thread_.task_runner(),
+      &VideoDecoderClient::DecodeDoneTask);
   decoder_->Decode(std::move(bitstream_buffer), std::move(decode_cb));
 
   num_outstanding_decode_requests_++;
@@ -304,8 +327,11 @@
   // Changing the state to flushing will abort any pending decodes.
   decoder_client_state_ = VideoDecoderClientState::kFlushing;
 
-  VideoDecoder::DecodeCB flush_done_cb = BindToCurrentLoop(
-      base::BindOnce(&VideoDecoderClient::FlushDoneTask, weak_this_));
+  VideoDecoder::DecodeCB flush_done_cb =
+      base::BindOnce(CallbackThunk<decltype(&VideoDecoderClient::FlushDoneTask),
+                                   media::DecodeStatus>,
+                     weak_this_, decoder_client_thread_.task_runner(),
+                     &VideoDecoderClient::FlushDoneTask);
   decoder_->Decode(DecoderBuffer::CreateEOSBuffer(), std::move(flush_done_cb));
 
   FireEvent(VideoPlayerEvent::kFlushing);
@@ -319,8 +345,10 @@
   decoder_client_state_ = VideoDecoderClientState::kResetting;
   // TODO(dstaessens@) Allow resetting to any point in the stream.
   encoded_data_helper_->Rewind();
-  base::RepeatingClosure reset_done_cb = BindToCurrentLoop(
-      base::BindRepeating(&VideoDecoderClient::ResetDoneTask, weak_this_));
+
+  base::RepeatingClosure reset_done_cb = base::BindRepeating(
+      CallbackThunk<decltype(&VideoDecoderClient::ResetDoneTask)>, weak_this_,
+      decoder_client_thread_.task_runner(), &VideoDecoderClient::ResetDoneTask);
   decoder_->Reset(reset_done_cb);
   FireEvent(VideoPlayerEvent::kResetting);
 }
@@ -393,6 +421,8 @@
 }
 
 void VideoDecoderClient::FireEvent(VideoPlayerEvent event) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_client_sequence_checker_);
+
   bool continue_decoding = event_cb_.Run(event);
   if (!continue_decoding) {
     // Changing the state to idle will abort any pending decodes.
diff --git a/media/gpu/test/video_player/video_player.cc b/media/gpu/test/video_player/video_player.cc
index 2f0382f..ecfa5b4 100644
--- a/media/gpu/test/video_player/video_player.cc
+++ b/media/gpu/test/video_player/video_player.cc
@@ -54,6 +54,9 @@
   CHECK(frame_renderer);
   DVLOGF(4);
 
+  // base::Unretained is safe here as we will never receive callbacks after
+  // destroying the video player, since the video decoder client will be
+  // destroyed first.
   EventCallback event_cb =
       base::BindRepeating(&VideoPlayer::NotifyEvent, base::Unretained(this));
 
diff --git a/media/gpu/v4l2/v4l2_device.cc b/media/gpu/v4l2/v4l2_device.cc
index 8189481..dbc406c 100644
--- a/media/gpu/v4l2/v4l2_device.cc
+++ b/media/gpu/v4l2/v4l2_device.cc
@@ -1153,14 +1153,6 @@
 }
 
 // static
-uint32_t V4L2Device::VideoFrameLayoutToV4L2PixFmt(
-    const VideoFrameLayout& layout) {
-  return Fourcc::FromVideoPixelFormat(layout.format(),
-                                      !layout.is_multi_planar())
-      .ToV4L2PixFmt();
-}
-
-// static
 uint32_t V4L2Device::VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile,
                                                    bool slice_based) {
   if (profile >= H264PROFILE_MIN && profile <= H264PROFILE_MAX) {
diff --git a/media/gpu/v4l2/v4l2_device.h b/media/gpu/v4l2/v4l2_device.h
index 0d06d93..862ed5f 100644
--- a/media/gpu/v4l2/v4l2_device.h
+++ b/media/gpu/v4l2/v4l2_device.h
@@ -381,9 +381,6 @@
     : public base::RefCountedThreadSafe<V4L2Device> {
  public:
   // Utility format conversion functions
-  // Returns v4l2 pixel format from |layout|. If there is no corresponding
-  // single- or multi-planar format or |layout| is invalid, returns 0.
-  static uint32_t VideoFrameLayoutToV4L2PixFmt(const VideoFrameLayout& layout);
   // If there is no corresponding single- or multi-planar format, returns 0.
   static uint32_t VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile,
                                                 bool slice_based);
diff --git a/media/gpu/v4l2/v4l2_image_processor.cc b/media/gpu/v4l2/v4l2_image_processor.cc
index c0fb718..75c607ff 100644
--- a/media/gpu/v4l2/v4l2_image_processor.cc
+++ b/media/gpu/v4l2/v4l2_image_processor.cc
@@ -18,6 +18,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/numerics/safe_conversions.h"
 #include "media/base/bind_to_current_loop.h"
+#include "media/base/color_plane_layout.h"
 #include "media/base/scopedfd_helper.h"
 #include "media/base/video_types.h"
 #include "media/gpu/chromeos/fourcc.h"
@@ -52,25 +53,15 @@
 
 V4L2ImageProcessor::V4L2ImageProcessor(
     scoped_refptr<V4L2Device> device,
-    VideoFrame::StorageType input_storage_type,
-    VideoFrame::StorageType output_storage_type,
+    const ImageProcessor::PortConfig& input_config,
+    const ImageProcessor::PortConfig& output_config,
     v4l2_memory input_memory_type,
     v4l2_memory output_memory_type,
     OutputMode output_mode,
-    const VideoFrameLayout& input_layout,
-    const VideoFrameLayout& output_layout,
-    gfx::Size input_visible_size,
-    gfx::Size output_visible_size,
     size_t num_buffers,
     ErrorCB error_cb)
-    : ImageProcessor(input_layout,
-                     input_storage_type,
-                     output_layout,
-                     output_storage_type,
-                     output_mode),
-      input_visible_size_(input_visible_size),
+    : ImageProcessor(input_config, output_config, output_mode),
       input_memory_type_(input_memory_type),
-      output_visible_size_(output_visible_size),
       output_memory_type_(output_memory_type),
       device_(device),
       device_thread_("V4L2ImageProcessorThread"),
@@ -172,20 +163,10 @@
     return nullptr;
   }
 
-  const VideoFrameLayout& input_layout = input_config.layout;
-
-  // Use input_config.fourcc as input format if it is specified, i.e. non-zero.
-  const uint32_t input_format_fourcc =
-      input_config.fourcc == ImageProcessor::PortConfig::kUnassignedFourCC
-          ? V4L2Device::VideoFrameLayoutToV4L2PixFmt(input_layout)
-          : input_config.fourcc;
-  if (!input_format_fourcc) {
-    VLOGF(1) << "Invalid VideoFrameLayout: " << input_layout;
-    return nullptr;
-  }
-  if (!device->Open(V4L2Device::Type::kImageProcessor, input_format_fourcc)) {
+  if (!device->Open(V4L2Device::Type::kImageProcessor,
+                    input_config.fourcc.ToV4L2PixFmt())) {
     VLOGF(1) << "Failed to open device with input fourcc: "
-             << FourccToString(input_format_fourcc);
+             << input_config.fourcc.ToString();
     return nullptr;
   }
 
@@ -193,77 +174,78 @@
   struct v4l2_format format;
   memset(&format, 0, sizeof(format));
   format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-  format.fmt.pix_mp.width = input_layout.coded_size().width();
-  format.fmt.pix_mp.height = input_layout.coded_size().height();
-  format.fmt.pix_mp.pixelformat = input_format_fourcc;
+  format.fmt.pix_mp.width = input_config.size.width();
+  format.fmt.pix_mp.height = input_config.size.height();
+  format.fmt.pix_mp.pixelformat = input_config.fourcc.ToV4L2PixFmt();
   if (device->Ioctl(VIDIOC_S_FMT, &format) != 0 ||
-      format.fmt.pix_mp.pixelformat != input_format_fourcc) {
+      format.fmt.pix_mp.pixelformat != input_config.fourcc.ToV4L2PixFmt()) {
     VLOGF(1) << "Failed to negotiate input format";
     return nullptr;
   }
 
-  base::Optional<VideoFrameLayout> negotiated_input_layout =
-      V4L2Device::V4L2FormatToVideoFrameLayout(format);
-  if (!negotiated_input_layout) {
-    VLOGF(1) << "Failed to negotiate input VideoFrameLayout";
-    return nullptr;
-  }
-
-  if (!gfx::Rect(negotiated_input_layout->coded_size())
+  const v4l2_pix_format_mplane& pix_mp = format.fmt.pix_mp;
+  const gfx::Size negotiated_input_size(pix_mp.width, pix_mp.height);
+  if (!gfx::Rect(negotiated_input_size)
            .Contains(gfx::Rect(input_config.visible_size))) {
     VLOGF(1) << "Negotiated input allocated size: "
-             << negotiated_input_layout->coded_size().ToString()
+             << negotiated_input_size.ToString()
              << " should contain visible size: "
              << input_config.visible_size.ToString();
     return nullptr;
   }
-
-  const VideoFrameLayout& output_layout = output_config.layout;
-  const uint32_t output_format_fourcc =
-      V4L2Device::VideoFrameLayoutToV4L2PixFmt(output_layout);
-  if (!output_format_fourcc) {
-    VLOGF(1) << "Invalid VideoFrameLayout: " << output_layout;
-    return nullptr;
+  std::vector<ColorPlaneLayout> input_planes(pix_mp.num_planes);
+  for (size_t i = 0; i < pix_mp.num_planes; ++i) {
+    input_planes[i].stride = pix_mp.plane_fmt[i].bytesperline;
+    // offset will be specified for a buffer in each VIDIOC_QBUF.
+    input_planes[i].offset = 0;
+    input_planes[i].size = pix_mp.plane_fmt[i].sizeimage;
   }
 
   // Try to set output format.
   memset(&format, 0, sizeof(format));
   format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-  format.fmt.pix_mp.width = output_layout.coded_size().width();
-  format.fmt.pix_mp.height = output_layout.coded_size().height();
-  format.fmt.pix_mp.pixelformat = output_format_fourcc;
-  format.fmt.pix_mp.num_planes =
-      V4L2Device::GetNumPlanesOfV4L2PixFmt(output_format_fourcc);
-  for (size_t i = 0; i < format.fmt.pix_mp.num_planes; ++i) {
-    format.fmt.pix_mp.plane_fmt[i].sizeimage = output_layout.planes()[i].size;
-    format.fmt.pix_mp.plane_fmt[i].bytesperline =
-        output_layout.planes()[i].stride;
+  v4l2_pix_format_mplane& out_pix_mp = format.fmt.pix_mp;
+  out_pix_mp.width = output_config.size.width();
+  out_pix_mp.height = output_config.size.height();
+  out_pix_mp.pixelformat = output_config.fourcc.ToV4L2PixFmt();
+  out_pix_mp.num_planes = output_config.planes.size();
+  for (size_t i = 0; i < output_config.planes.size(); ++i) {
+    out_pix_mp.plane_fmt[i].sizeimage = output_config.planes[i].size;
+    out_pix_mp.plane_fmt[i].bytesperline = output_config.planes[i].stride;
   }
   if (device->Ioctl(VIDIOC_S_FMT, &format) != 0 ||
-      format.fmt.pix_mp.pixelformat != output_format_fourcc) {
+      format.fmt.pix_mp.pixelformat != output_config.fourcc.ToV4L2PixFmt()) {
     VLOGF(1) << "Failed to negotiate output format";
     return nullptr;
   }
-  base::Optional<VideoFrameLayout> negotiated_output_layout =
-      V4L2Device::V4L2FormatToVideoFrameLayout(format);
-  if (!negotiated_output_layout) {
-    VLOGF(1) << "Failed to negotiate output VideoFrameLayout";
+
+  out_pix_mp = format.fmt.pix_mp;
+  const gfx::Size negotiated_output_size(out_pix_mp.width, out_pix_mp.height);
+  if (!gfx::Rect(negotiated_output_size)
+           .Contains(gfx::Rect(output_config.size))) {
+    VLOGF(1) << "Negotiated output allocated size: "
+             << negotiated_output_size.ToString()
+             << " should contain original output allocated size: "
+             << output_config.size.ToString();
     return nullptr;
   }
-  if (!gfx::Rect(negotiated_output_layout->coded_size())
-           .Contains(gfx::Rect(output_layout.coded_size()))) {
-    VLOGF(1) << "Negotiated output allocated size: "
-             << negotiated_output_layout->coded_size().ToString()
-             << " should contain original output allocated size: "
-             << output_layout.coded_size().ToString();
-    return nullptr;
+  std::vector<ColorPlaneLayout> output_planes(out_pix_mp.num_planes);
+  for (size_t i = 0; i < pix_mp.num_planes; ++i) {
+    output_planes[i].stride = pix_mp.plane_fmt[i].bytesperline;
+    // offset will be specified for a buffer in each VIDIOC_QBUF.
+    output_planes[i].offset = 0;
+    output_planes[i].size = pix_mp.plane_fmt[i].sizeimage;
   }
 
   auto processor = base::WrapUnique(new V4L2ImageProcessor(
-      std::move(device), input_storage_type, output_storage_type,
-      input_memory_type, output_memory_type, output_mode,
-      *negotiated_input_layout, *negotiated_output_layout,
-      input_config.visible_size, output_config.visible_size, num_buffers,
+      std::move(device),
+      ImageProcessor::PortConfig(input_config.fourcc, negotiated_input_size,
+                                 input_planes, input_config.visible_size,
+                                 {input_storage_type}),
+      ImageProcessor::PortConfig(output_config.fourcc, negotiated_output_size,
+                                 output_planes, output_config.visible_size,
+                                 {output_storage_type}),
+      input_memory_type, output_memory_type, output_mode, num_buffers,
       media::BindToCurrentLoop(std::move(error_cb))));
   if (!processor->Initialize()) {
     VLOGF(1) << "Failed to initialize V4L2ImageProcessor";
@@ -306,10 +288,8 @@
                                 base::Unretained(this)));
 
   VLOGF(2) << "V4L2ImageProcessor initialized for "
-           << "input_layout: " << input_layout_
-           << ", output_layout: " << output_layout_
-           << ", input_visible_size: " << input_visible_size_.ToString()
-           << ", output_visible_size: " << output_visible_size_.ToString();
+           << "input: " << input_config_.ToString()
+           << ", output: " << output_config_.ToString();
 
   return true;
 }
@@ -514,8 +494,10 @@
   struct v4l2_rect visible_rect;
   visible_rect.left = 0;
   visible_rect.top = 0;
-  visible_rect.width = base::checked_cast<__u32>(input_visible_size_.width());
-  visible_rect.height = base::checked_cast<__u32>(input_visible_size_.height());
+  visible_rect.width =
+      base::checked_cast<__u32>(input_config_.visible_size.width());
+  visible_rect.height =
+      base::checked_cast<__u32>(input_config_.visible_size.height());
 
   struct v4l2_selection selection_arg;
   memset(&selection_arg, 0, sizeof(selection_arg));
@@ -556,9 +538,10 @@
   struct v4l2_rect visible_rect;
   visible_rect.left = 0;
   visible_rect.top = 0;
-  visible_rect.width = base::checked_cast<__u32>(output_visible_size_.width());
+  visible_rect.width =
+      base::checked_cast<__u32>(output_config_.visible_size.width());
   visible_rect.height =
-    base::checked_cast<__u32>(output_visible_size_.height());
+      base::checked_cast<__u32>(output_config_.visible_size.height());
 
   output_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
   if (!output_queue_)
@@ -796,11 +779,11 @@
   DCHECK(buffer.IsValid());
 
   std::vector<void*> user_ptrs;
-  size_t num_planes = V4L2Device::GetNumPlanesOfV4L2PixFmt(
-      V4L2Device::VideoFrameLayoutToV4L2PixFmt(input_layout_));
+  const size_t num_planes =
+      V4L2Device::GetNumPlanesOfV4L2PixFmt(input_config_.fourcc.ToV4L2PixFmt());
   for (size_t i = 0; i < num_planes; ++i) {
     int bytes_used = VideoFrame::PlaneSize(job_record->input_frame->format(), i,
-                                           input_layout_.coded_size())
+                                           input_config_.size)
                          .GetArea();
     buffer.SetPlaneBytesUsed(i, bytes_used);
     if (buffer.Memory() == V4L2_MEMORY_USERPTR)
diff --git a/media/gpu/v4l2/v4l2_image_processor.h b/media/gpu/v4l2/v4l2_image_processor.h
index cc1483fd..1d85f3b 100644
--- a/media/gpu/v4l2/v4l2_image_processor.h
+++ b/media/gpu/v4l2/v4l2_image_processor.h
@@ -92,15 +92,11 @@
   };
 
   V4L2ImageProcessor(scoped_refptr<V4L2Device> device,
-                     VideoFrame::StorageType input_storage_type,
-                     VideoFrame::StorageType output_storage_type,
+                     const ImageProcessor::PortConfig& input_config,
+                     const ImageProcessor::PortConfig& output_config,
                      v4l2_memory input_memory_type,
                      v4l2_memory output_memory_type,
                      OutputMode output_mode,
-                     const VideoFrameLayout& input_layout,
-                     const VideoFrameLayout& output_layout,
-                     gfx::Size input_visible_size,
-                     gfx::Size output_visible_size,
                      size_t num_buffers,
                      ErrorCB error_cb);
 
@@ -143,12 +139,7 @@
   // callbacks will be invoked.
   void Destroy();
 
-  // Stores input frame's visible size and v4l2_memory type.
-  const gfx::Size input_visible_size_;
   const v4l2_memory input_memory_type_;
-
-  // Stores output frame's visible size and v4l2_memory type.
-  const gfx::Size output_visible_size_;
   const v4l2_memory output_memory_type_;
 
   // V4L2 device in use.
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index f75ebb1..a013d21 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -585,7 +585,7 @@
     return false;
   }
 
-  DCHECK_EQ(gl_image_size_, image_processor_->output_layout().coded_size());
+  DCHECK_EQ(gl_image_size_, image_processor_->output_config().size);
 
   return true;
 }
diff --git a/media/gpu/v4l2/v4l2_vda_helpers.cc b/media/gpu/v4l2/v4l2_vda_helpers.cc
index a01d9cf..f73d4e94 100644
--- a/media/gpu/v4l2/v4l2_vda_helpers.cc
+++ b/media/gpu/v4l2/v4l2_vda_helpers.cc
@@ -13,38 +13,6 @@
 namespace media {
 namespace v4l2_vda_helpers {
 
-namespace {
-base::Optional<VideoFrameLayout> CreateLayout(uint32_t fourcc,
-                                              const gfx::Size& size) {
-  // V4L2 specific format hack:
-  // If VDA's output format is V4L2_PIX_FMT_MT21C, which is a platform specific
-  // format and now is only used for MT8173 VDA output and its image processor
-  // input, we set VideoFrameLayout for image processor's input with format
-  // PIXEL_FORMAT_NV12 as NV12's layout is the same as MT21.
-  size_t num_planes;
-  switch (fourcc) {
-    case V4L2_PIX_FMT_MT21C:
-    case V4L2_PIX_FMT_MM21:
-      num_planes = 2;
-      return VideoFrameLayout::CreateMultiPlanar(
-          PIXEL_FORMAT_NV12, size, std::vector<ColorPlaneLayout>(num_planes));
-
-    default:
-      VideoPixelFormat pixel_format =
-          Fourcc::FromV4L2PixFmt(fourcc).ToVideoPixelFormat();
-      if (pixel_format == PIXEL_FORMAT_UNKNOWN)
-        return base::nullopt;
-      num_planes = V4L2Device::GetNumPlanesOfV4L2PixFmt(fourcc);
-      if (num_planes == 1)
-        return VideoFrameLayout::Create(pixel_format, size);
-      else
-        return VideoFrameLayout::CreateMultiPlanar(
-            pixel_format, size, std::vector<ColorPlaneLayout>(num_planes));
-      break;
-  }
-}
-}  // namespace
-
 uint32_t FindImageProcessorInputFormat(V4L2Device* vda_device) {
   std::vector<uint32_t> processor_input_formats =
       V4L2ImageProcessor::GetSupportedInputFormats();
@@ -103,45 +71,33 @@
     scoped_refptr<V4L2Device> image_processor_device,
     ImageProcessor::OutputMode image_processor_output_mode,
     ImageProcessor::ErrorCB error_cb) {
-  base::Optional<VideoFrameLayout> input_layout =
-      CreateLayout(vda_output_format, vda_output_coded_size);
-  if (!input_layout) {
-    VLOGF(1) << "Invalid input layout";
-    return nullptr;
-  }
-
-  base::Optional<VideoFrameLayout> output_layout =
-      CreateLayout(ip_output_format, ip_output_coded_size);
-  if (!output_layout) {
-    VLOGF(1) << "Invalid output layout";
-    return nullptr;
-  }
-
   // TODO(crbug.com/917798): Use ImageProcessorFactory::Create() once we remove
   //     |image_processor_device_| from V4L2VideoDecodeAccelerator.
   auto image_processor = V4L2ImageProcessor::Create(
       image_processor_device,
-      ImageProcessor::PortConfig(*input_layout, vda_output_format, visible_size,
+      ImageProcessor::PortConfig(Fourcc::FromV4L2PixFmt(vda_output_format),
+                                 vda_output_coded_size, {}, visible_size,
                                  {VideoFrame::STORAGE_DMABUFS}),
-      ImageProcessor::PortConfig(*output_layout, visible_size,
+      ImageProcessor::PortConfig(Fourcc::FromV4L2PixFmt(ip_output_format),
+                                 ip_output_coded_size, {}, visible_size,
                                  {VideoFrame::STORAGE_DMABUFS}),
       image_processor_output_mode, nb_buffers, std::move(error_cb));
   if (!image_processor)
     return nullptr;
 
-  if (image_processor->output_layout().coded_size() != ip_output_coded_size) {
+  if (image_processor->output_config().size != ip_output_coded_size) {
     VLOGF(1) << "Image processor should be able to use the requested output "
              << "coded size " << ip_output_coded_size.ToString()
              << " without adjusting to "
-             << image_processor->output_layout().coded_size().ToString();
+             << image_processor->output_config().size.ToString();
     return nullptr;
   }
 
-  if (image_processor->input_layout().coded_size() != vda_output_coded_size) {
+  if (image_processor->input_config().size != vda_output_coded_size) {
     VLOGF(1) << "Image processor should be able to take the output coded "
              << "size of decoder " << vda_output_coded_size.ToString()
              << " without adjusting to "
-             << image_processor->input_layout().coded_size().ToString();
+             << image_processor->input_config().size.ToString();
     return nullptr;
   }
 
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
index 2197bec..b3face6b 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
@@ -96,6 +96,19 @@
 
 namespace media {
 
+namespace {
+// Convert VideoFrameLayout to ImageProcessor::PortConfig.
+ImageProcessor::PortConfig VideoFrameLayoutToPortConfig(
+    const VideoFrameLayout& layout,
+    const gfx::Size& visible_size,
+    const std::vector<VideoFrame::StorageType>& preferred_storage_types) {
+  return ImageProcessor::PortConfig(
+      Fourcc::FromVideoPixelFormat(layout.format(), !layout.is_multi_planar()),
+      layout.coded_size(), layout.planes(), visible_size,
+      preferred_storage_types);
+}
+}  // namespace
+
 struct V4L2VideoEncodeAccelerator::BitstreamBufferRef {
   BitstreamBufferRef(int32_t id, std::unique_ptr<UnalignedSharedMemory> shm)
       : id(id), shm(std::move(shm)) {}
@@ -267,12 +280,12 @@
       config.initial_bitrate, config.initial_framerate.value_or(
                                   VideoEncodeAccelerator::kDefaultFramerate));
   child_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &Client::RequireBitstreamBuffers, client_, kInputBufferCount,
-          image_processor_.get() ? image_processor_->input_layout().coded_size()
-                                 : input_allocated_size_,
-          output_buffer_byte_size_));
+      FROM_HERE, base::BindOnce(&Client::RequireBitstreamBuffers, client_,
+                                kInputBufferCount,
+                                image_processor_.get()
+                                    ? image_processor_->input_config().size
+                                    : input_allocated_size_,
+                                output_buffer_byte_size_));
 
   // Finish initialization.
   *result = true;
@@ -294,9 +307,9 @@
   // for |input_storage_type| here, as long as VideoFrame on Process()'s data
   // can be accessed by VideoFrame::data().
   image_processor_ = ImageProcessorFactory::Create(
-      ImageProcessor::PortConfig(input_layout, visible_size,
-                                 {VideoFrame::STORAGE_OWNED_MEMORY}),
-      ImageProcessor::PortConfig(
+      VideoFrameLayoutToPortConfig(input_layout, visible_size,
+                                   {VideoFrame::STORAGE_OWNED_MEMORY}),
+      VideoFrameLayoutToPortConfig(
           output_layout, visible_size,
           {VideoFrame::STORAGE_DMABUFS, VideoFrame::STORAGE_OWNED_MEMORY}),
       // Try OutputMode::ALLOCATE first because we want v4l2IP chooses
@@ -319,7 +332,7 @@
   // Output coded height of processor can be larger but not smaller than the
   // input coded height of encoder. For example, suppose input size of encoder
   // is 320x193. It is OK if the output of processor is 320x208.
-  const auto& ip_output_size = image_processor_->output_layout().coded_size();
+  const auto& ip_output_size = image_processor_->output_config().size;
   if (ip_output_size.width() != output_layout.coded_size().width() ||
       ip_output_size.height() < output_layout.coded_size().height()) {
     VLOGF(1) << "Invalid image processor output coded size "
@@ -347,7 +360,8 @@
   }
 
   image_processor_output_buffers_.resize(count);
-  const auto output_storage_type = image_processor_->output_storage_type();
+  const auto output_storage_type =
+      image_processor_->output_config().storage_type();
   for (size_t i = 0; i < count; i++) {
     switch (output_storage_type) {
       case VideoFrame::STORAGE_OWNED_MEMORY:
@@ -372,7 +386,7 @@
 bool V4L2VideoEncodeAccelerator::InitInputMemoryType(const Config& config) {
   DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread());
   if (image_processor_) {
-    const auto storage_type = image_processor_->output_storage_type();
+    const auto storage_type = image_processor_->output_config().storage_type();
     if (storage_type == VideoFrame::STORAGE_DMABUFS) {
       input_memory_type_ = V4L2_MEMORY_DMABUF;
     } else if (VideoFrame::IsStorageTypeMappable(storage_type)) {
@@ -640,7 +654,7 @@
   // We should apply the frame size change to ImageProcessor if there is.
   if (image_processor_) {
     // Stride is the same. There is no need of executing S_FMT again.
-    if (image_processor_->input_layout().coded_size() == new_frame_size) {
+    if (image_processor_->input_config().size == new_frame_size) {
       return true;
     }
 
@@ -667,7 +681,7 @@
       NOTIFY_ERROR(kPlatformFailureError);
       return false;
     }
-    if (image_processor_->input_layout().coded_size().width() !=
+    if (image_processor_->input_config().size.width() !=
         new_frame_size.width()) {
       NOTIFY_ERROR(kPlatformFailureError);
       return false;
@@ -1068,7 +1082,9 @@
 
   DCHECK_EQ(device_input_layout_->format(), frame->format());
   size_t num_planes = V4L2Device::GetNumPlanesOfV4L2PixFmt(
-      V4L2Device::VideoFrameLayoutToV4L2PixFmt(*device_input_layout_));
+      Fourcc::FromVideoPixelFormat(device_input_layout_->format(),
+                                   device_input_layout_->is_multi_planar())
+          .ToV4L2PixFmt());
 
   // Create GpuMemoryBufferHandle for native_input_mode.
   gfx::GpuMemoryBufferHandle gmb_handle;
diff --git a/media/gpu/vaapi/vaapi_image_processor.cc b/media/gpu/vaapi/vaapi_image_processor.cc
index 52ee551b..885a0b8 100644
--- a/media/gpu/vaapi/vaapi_image_processor.cc
+++ b/media/gpu/vaapi/vaapi_image_processor.cc
@@ -4,6 +4,8 @@
 
 #include "media/gpu/vaapi/vaapi_image_processor.h"
 
+#include <stdint.h>
+
 #include <va/va.h>
 
 #include "base/bind.h"
@@ -35,23 +37,19 @@
   error_cb.Run();
 }
 
-bool IsSupported(VideoPixelFormat input_format,
-                 VideoPixelFormat output_format,
-                 gfx::Size input_size,
-                 gfx::Size output_size) {
-  const uint32_t input_va_fourcc =
-      Fourcc::FromVideoPixelFormat(input_format).ToVAFourCC();
+bool IsSupported(uint32_t input_va_fourcc,
+                 uint32_t output_va_fourcc,
+                 const gfx::Size& input_size,
+                 const gfx::Size& output_size) {
   if (!VaapiWrapper::IsVppFormatSupported(input_va_fourcc)) {
-    VLOGF(2) << "Unsupported input format: " << input_format << " (VA_FOURCC_"
-             << FourccToString(input_va_fourcc) << ")";
+    VLOGF(2) << "Unsupported input format: VA_FOURCC_"
+             << FourccToString(input_va_fourcc);
     return false;
   }
 
-  const uint32_t output_va_fourcc =
-      Fourcc::FromVideoPixelFormat(output_format).ToVAFourCC();
   if (!VaapiWrapper::IsVppFormatSupported(output_va_fourcc)) {
-    VLOGF(2) << "Unsupported output format: " << output_format << " (VA_FOURCC_"
-             << FourccToString(output_va_fourcc) << ")";
+    VLOGF(2) << "Unsupported output format: VA_FOURCC_"
+             << FourccToString(output_va_fourcc);
     return false;
   }
 
@@ -101,11 +99,9 @@
   return nullptr;
 #endif
 
-  const VideoFrameLayout& input_layout = input_config.layout;
-  const VideoFrameLayout& output_layout = output_config.layout;
-  if (!IsSupported(input_layout.format(), output_layout.format(),
-                   input_config.layout.coded_size(),
-                   output_config.layout.coded_size())) {
+  if (!IsSupported(input_config.fourcc.ToVAFourCC(),
+                   output_config.fourcc.ToVAFourCC(), input_config.size,
+                   output_config.size)) {
     return nullptr;
   }
 
@@ -131,27 +127,23 @@
     return nullptr;
   }
 
-  // We should restrict the acceptable VideoFrameLayout for input and output
-  // both to the one returned by GetPlatformVideoFrameLayout(). However,
+  // We should restrict the acceptable PortConfig for input and output both to
+  // the one returned by GetPlatformVideoFrameLayout(). However,
   // ImageProcessorFactory interface doesn't provide information about what
   // ImageProcessor will be used for. (e.g. format conversion after decoding and
   // scaling before encoding). Thus we cannot execute
   // GetPlatformVideoFrameLayout() with a proper gfx::BufferUsage.
   // TODO(crbug.com/898423): Adjust layout once ImageProcessor provide the use
   // scenario.
-  return base::WrapUnique(new VaapiImageProcessor(input_layout, output_layout,
+  return base::WrapUnique(new VaapiImageProcessor(input_config, output_config,
                                                   std::move(vaapi_wrapper)));
 }
 
 VaapiImageProcessor::VaapiImageProcessor(
-    const VideoFrameLayout& input_layout,
-    const VideoFrameLayout& output_layout,
+    const ImageProcessor::PortConfig& input_config,
+    const ImageProcessor::PortConfig& output_config,
     scoped_refptr<VaapiWrapper> vaapi_wrapper)
-    : ImageProcessor(input_layout,
-                     VideoFrame::STORAGE_DMABUFS,
-                     output_layout,
-                     VideoFrame::STORAGE_DMABUFS,
-                     OutputMode::IMPORT),
+    : ImageProcessor(input_config, output_config, OutputMode::IMPORT),
       processor_task_runner_(base::CreateSequencedTaskRunner(
           base::TaskTraits{base::ThreadPool()})),
       vaapi_wrapper_(std::move(vaapi_wrapper)) {}
@@ -169,32 +161,46 @@
   DCHECK(input_frame);
   DCHECK(output_frame);
 
-  const VideoFrameLayout& input_frame_layout = input_frame->layout();
-  if (input_frame_layout.format() != input_layout_.format() ||
-      input_frame_layout.coded_size() != input_layout_.coded_size()) {
-    VLOGF(1) << "Invalid input_frame->layout=" << input_frame->layout()
-             << ", input_layout_=" << input_layout_;
+  const Fourcc input_frame_fourcc =
+      Fourcc::FromVideoPixelFormat(input_frame->layout().format());
+  if (input_frame_fourcc != input_config_.fourcc) {
+    VLOGF(1) << "Invalid input_frame format=" << input_frame_fourcc.ToString()
+             << ", expected=" << input_config_.fourcc.ToString();
     return false;
   }
 
-  const VideoFrameLayout& output_frame_layout = output_frame->layout();
-  if (output_frame_layout.format() != output_layout_.format() ||
-      output_frame_layout.coded_size() != output_layout_.coded_size()) {
-    VLOGF(1) << "Invalid output_frame->layout=" << output_frame->layout()
-             << ", output_layout_=" << output_layout_;
+  if (input_frame->layout().coded_size() != input_config_.size) {
+    VLOGF(1) << "Invalid input_frame size="
+             << input_frame->layout().coded_size().ToString()
+             << ", expected=" << input_config_.size.ToString();
     return false;
   }
 
-  if (input_frame->storage_type() != input_storage_type()) {
+  const Fourcc output_frame_fourcc =
+      Fourcc::FromVideoPixelFormat(output_frame->layout().format());
+  if (output_frame_fourcc != output_config_.fourcc) {
+    VLOGF(1) << "Invalid output_frame format=" << output_frame_fourcc.ToString()
+             << ", expected=" << output_config_.fourcc.ToString();
+    return false;
+  }
+
+  if (output_frame->layout().coded_size() != output_config_.size) {
+    VLOGF(1) << "Invalid output_frame size="
+             << output_frame->layout().coded_size().ToString()
+             << ", expected=" << output_config_.size.ToString();
+    return false;
+  }
+
+  if (input_frame->storage_type() != input_config_.storage_type()) {
     VLOGF(1) << "Invalid input_frame->storage_type="
              << input_frame->storage_type()
-             << ", input_storage_type=" << input_storage_type();
+             << ", input_storage_type=" << input_config_.storage_type();
     return false;
   }
-  if (output_frame->storage_type() != output_storage_type()) {
+  if (output_frame->storage_type() != output_config_.storage_type()) {
     VLOGF(1) << "Invalid output_frame->storage_type="
              << output_frame->storage_type()
-             << ", output_storage_type=" << output_storage_type();
+             << ", expected=" << output_config_.storage_type();
     return false;
   }
 
diff --git a/media/gpu/vaapi/vaapi_image_processor.h b/media/gpu/vaapi/vaapi_image_processor.h
index 69a0082b..699be4c2 100644
--- a/media/gpu/vaapi/vaapi_image_processor.h
+++ b/media/gpu/vaapi/vaapi_image_processor.h
@@ -39,8 +39,8 @@
   bool Reset() override;
 
  private:
-  VaapiImageProcessor(const VideoFrameLayout& input_layout,
-                      const VideoFrameLayout& output_layout,
+  VaapiImageProcessor(const ImageProcessor::PortConfig& input_config,
+                      const ImageProcessor::PortConfig& output_config,
                       scoped_refptr<VaapiWrapper> vaapi_wrapper);
 
   // ImageProcessor implementation.
diff --git a/media/gpu/windows/d3d11_copying_texture_wrapper.cc b/media/gpu/windows/d3d11_copying_texture_wrapper.cc
index e84986f..4b00827 100644
--- a/media/gpu/windows/d3d11_copying_texture_wrapper.cc
+++ b/media/gpu/windows/d3d11_copying_texture_wrapper.cc
@@ -61,7 +61,6 @@
 
 bool CopyingTexture2DWrapper::Init(GetCommandBufferHelperCB get_helper_cb,
                                    size_t array_slice,
-                                   GLenum target,
                                    gfx::Size size,
                                    int textures_per_picture) {
   if (!video_processor_->Init(size.width(), size.height()))
@@ -70,7 +69,7 @@
   return output_texture_wrapper_->Init(
       get_helper_cb,
       0,  // The output texture only has an array size of 1.
-      target, size, textures_per_picture);
+      size, textures_per_picture);
 }
 
 }  // namespace media
diff --git a/media/gpu/windows/d3d11_copying_texture_wrapper.h b/media/gpu/windows/d3d11_copying_texture_wrapper.h
index 6524ea0..81663f8 100644
--- a/media/gpu/windows/d3d11_copying_texture_wrapper.h
+++ b/media/gpu/windows/d3d11_copying_texture_wrapper.h
@@ -30,7 +30,6 @@
 
   bool Init(GetCommandBufferHelperCB get_helper_cb,
             size_t array_slice,
-            GLenum target,
             gfx::Size size,
             int textures_per_picture) override;
 
diff --git a/media/gpu/windows/d3d11_copying_texture_wrapper_unittest.cc b/media/gpu/windows/d3d11_copying_texture_wrapper_unittest.cc
index 33ed3e4..89537bd4 100644
--- a/media/gpu/windows/d3d11_copying_texture_wrapper_unittest.cc
+++ b/media/gpu/windows/d3d11_copying_texture_wrapper_unittest.cc
@@ -65,7 +65,6 @@
 
   bool Init(GetCommandBufferHelperCB get_helper_cb,
             size_t array_slice,
-            GLenum target,
             gfx::Size size,
             int textures_per_picture) override {
     return MockInit();
@@ -153,10 +152,10 @@
        CopyingTextureWrapperProcessesCorrectly) {
   auto wrapper = std::make_unique<CopyingTexture2DWrapper>(
       ExpectTextureWrapper(), ExpectProcessorProxy(), nullptr);
-  auto picture_buffer = base::MakeRefCounted<D3D11PictureBuffer>(
-      GL_TEXTURE_EXTERNAL_OES, nullptr, gfx::Size(0, 0), 0);
+  auto picture_buffer =
+      base::MakeRefCounted<D3D11PictureBuffer>(nullptr, gfx::Size(0, 0), 0);
 
-  EXPECT_EQ(wrapper->Init(CreateMockHelperCB(), 0, {}, {}, 0), InitSucceeds());
+  EXPECT_EQ(wrapper->Init(CreateMockHelperCB(), 0, {}, 0), InitSucceeds());
   EXPECT_EQ(wrapper->ProcessTexture(picture_buffer.get(), nullptr),
             ProcessTextureSucceeds());
 }
diff --git a/media/gpu/windows/d3d11_picture_buffer.cc b/media/gpu/windows/d3d11_picture_buffer.cc
index 781e873..27a6f1f 100644
--- a/media/gpu/windows/d3d11_picture_buffer.cc
+++ b/media/gpu/windows/d3d11_picture_buffer.cc
@@ -22,12 +22,10 @@
 namespace media {
 
 D3D11PictureBuffer::D3D11PictureBuffer(
-    GLenum target,
     std::unique_ptr<Texture2DWrapper> texture_wrapper,
     gfx::Size size,
     size_t level)
-    : target_(target),
-      texture_wrapper_(std::move(texture_wrapper)),
+    : texture_wrapper_(std::move(texture_wrapper)),
       size_(size),
       level_(level) {}
 
@@ -45,7 +43,7 @@
   view_desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
   view_desc.Texture2D.ArraySlice = (UINT)level_;
 
-  if (!texture_wrapper_->Init(std::move(get_helper_cb), level_, target_, size_,
+  if (!texture_wrapper_->Init(std::move(get_helper_cb), level_, size_,
                               textures_per_picture)) {
     media_log->AddEvent(
         media_log->CreateStringEvent(MediaLogEvent::MEDIA_ERROR_LOG_ENTRY,
diff --git a/media/gpu/windows/d3d11_picture_buffer.h b/media/gpu/windows/d3d11_picture_buffer.h
index 8358a18..5f94511 100644
--- a/media/gpu/windows/d3d11_picture_buffer.h
+++ b/media/gpu/windows/d3d11_picture_buffer.h
@@ -49,8 +49,7 @@
   // |texture_wrapper| is responsible for controlling mailbox access to
   // the ID3D11Texture2D,
   // |level| is the picturebuffer index inside the Array-type ID3D11Texture2D.
-  D3D11PictureBuffer(GLenum target,
-                     std::unique_ptr<Texture2DWrapper> texture_wrapper,
+  D3D11PictureBuffer(std::unique_ptr<Texture2DWrapper> texture_wrapper,
                      gfx::Size size,
                      size_t level);
 
@@ -87,7 +86,6 @@
   ~D3D11PictureBuffer();
   friend class base::RefCountedThreadSafe<D3D11PictureBuffer>;
 
-  GLenum target_;
   std::unique_ptr<Texture2DWrapper> texture_wrapper_;
   gfx::Size size_;
   bool in_picture_use_ = false;
diff --git a/media/gpu/windows/d3d11_texture_wrapper.cc b/media/gpu/windows/d3d11_texture_wrapper.cc
index 9776f8f..8a7e8ce 100644
--- a/media/gpu/windows/d3d11_texture_wrapper.cc
+++ b/media/gpu/windows/d3d11_texture_wrapper.cc
@@ -33,7 +33,6 @@
 
 bool DefaultTexture2DWrapper::Init(GetCommandBufferHelperCB get_helper_cb,
                                    size_t array_slice,
-                                   GLenum target,
                                    gfx::Size size,
                                    int textures_per_picture) {
   gpu_resources_ = std::make_unique<GpuResources>();
@@ -55,8 +54,8 @@
   // a handle that we get from |texture| as an IDXGIResource1.
   // TODO(liberato): this should happen on the gpu thread.
   return gpu_resources_->Init(std::move(get_helper_cb), array_slice,
-                              std::move(mailboxes), target, size, Texture(),
-                              textures_per_picture);
+                              std::move(mailboxes), GL_TEXTURE_EXTERNAL_OES,
+                              size, Texture(), textures_per_picture);
 
   return true;
 }
diff --git a/media/gpu/windows/d3d11_texture_wrapper.h b/media/gpu/windows/d3d11_texture_wrapper.h
index b3ac8c4a..0f309403 100644
--- a/media/gpu/windows/d3d11_texture_wrapper.h
+++ b/media/gpu/windows/d3d11_texture_wrapper.h
@@ -51,7 +51,6 @@
   // Texture2D. It is 1 otherwise.
   virtual bool Init(GetCommandBufferHelperCB get_helper_cb,
                     size_t array_slice,
-                    GLenum target,
                     gfx::Size size,
                     int textures_per_picture) = 0;
 
@@ -68,7 +67,6 @@
 
   bool Init(GetCommandBufferHelperCB get_helper_cb,
             size_t array_slice,
-            GLenum target,
             gfx::Size size,
             int textures_per_picture) override;
 
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc
index 22257bf..2e9b88c 100644
--- a/media/gpu/windows/d3d11_video_decoder.cc
+++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -617,8 +617,8 @@
     auto tex_wrapper = texture_selector_->CreateTextureWrapper(
         device_, video_device_, device_context_, in_texture, size);
 
-    picture_buffers_.push_back(new D3D11PictureBuffer(
-        GL_TEXTURE_EXTERNAL_OES, std::move(tex_wrapper), size, i));
+    picture_buffers_.push_back(
+        new D3D11PictureBuffer(std::move(tex_wrapper), size, i));
     if (!picture_buffers_[i]->Init(get_helper_cb_, video_device_,
                                    texture_selector_->DecoderGuid(),
                                    textures_per_picture, media_log_->Clone())) {
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
index ac986b28..a5c986b 100644
--- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -354,6 +354,8 @@
     }
   }
 
+  // TODO(sandersd): Update to match logic in VTVDA that tracks activated rather
+  // than most recent SPS and PPS.
   if (!sps.empty() && sps != last_sps_) {
     if (!last_sps_.empty()) {
       // Flag configuration changes after we see an IDR slice.
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc
index e55a2f0..a20127a 100644
--- a/media/renderers/paint_canvas_video_renderer.cc
+++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -564,8 +564,6 @@
   }
   ~VideoImageGenerator() override = default;
 
-  bool IsEligibleForAcceleratedDecoding() const override { return false; }
-
   sk_sp<SkData> GetEncodedData() const override { return nullptr; }
 
   bool GetPixels(const SkImageInfo& info,
diff --git a/media/video/h264_parser.cc b/media/video/h264_parser.cc
index 75d7196..f00faf32 100644
--- a/media/video/h264_parser.cc
+++ b/media/video/h264_parser.cc
@@ -1219,6 +1219,19 @@
   return kOk;
 }
 
+H264Parser::Result H264Parser::ParseSPSExt(int* sps_id) {
+  // See 7.4.2.1.
+  int local_sps_id = -1;
+
+  *sps_id = -1;
+
+  READ_UE_OR_RETURN(&local_sps_id);
+  TRUE_OR_RETURN(local_sps_id < 32);
+
+  *sps_id = local_sps_id;
+  return kOk;
+}
+
 H264Parser::Result H264Parser::ParseRefPicListModification(
     int num_ref_idx_active_minus1,
     H264ModificationOfPicNum* ref_list_mods) {
diff --git a/media/video/h264_parser.h b/media/video/h264_parser.h
index 4a701fe6..f7439fe 100644
--- a/media/video/h264_parser.h
+++ b/media/video/h264_parser.h
@@ -466,6 +466,9 @@
   Result ParseSPS(int* sps_id);
   Result ParsePPS(int* pps_id);
 
+  // Parses the SPS ID from the SPSExt, but otherwise does nothing.
+  Result ParseSPSExt(int* sps_id);
+
   // Return a pointer to SPS/PPS with given |sps_id|/|pps_id| or NULL if not
   // present.
   const H264SPS* GetSPS(int sps_id) const;
diff --git a/mojo/public/js/compile_preamble.js b/mojo/public/js/compile_preamble.js
index f2cd699..497e14d 100644
--- a/mojo/public/js/compile_preamble.js
+++ b/mojo/public/js/compile_preamble.js
@@ -7,6 +7,8 @@
  * @fileoverview Preamble for JavaScript to be compiled with Closure Compiler.
  * We don't comple against the Closure library, so this provides a minimal set
  * of 'goog' namespace properties to support things like symbol exports.
+ *
+ * @provideGoog
  */
 
 /** @const */
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 66f481c..f32b0c05 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -5087,6 +5087,7 @@
     "base/lookup_string_in_fixed_set_unittest.cc",
     "base/mime_sniffer_unittest.cc",
     "base/mime_util_unittest.cc",
+    "base/net_errors_unittest.cc",
     "base/net_string_util_unittest.cc",
     "base/network_activity_monitor_unittest.cc",
     "base/network_change_notifier_unittest.cc",
diff --git a/net/base/cache_type.h b/net/base/cache_type.h
index f7eb3a1..3f2989b 100644
--- a/net/base/cache_type.h
+++ b/net/base/cache_type.h
@@ -8,10 +8,12 @@
 namespace net {
 
 // The types of caches that can be created.
+// Note: enum values used in some metrics, so add new values at end only,
+// and don't renumber old ones.
 enum CacheType {
   DISK_CACHE,                 // Disk is used as the backing storage.
   MEMORY_CACHE,               // Data is stored only in memory.
-  MEDIA_CACHE,                // Optimized to handle media files.
+  REMOVED_MEDIA_CACHE,        // No longer in use.
   APP_CACHE,                  // Backing store for an AppCache.
   SHADER_CACHE,               // Backing store for the GL shader cache.
   PNACL_CACHE,                // Backing store the PNaCl translation cache
diff --git a/net/base/features.cc b/net/base/features.cc
index 0bce309e..8746d27 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -15,9 +15,6 @@
 const base::FeatureParam<int> kMaxRefererHeaderLength = {
     &kCapRefererHeaderLength, "MaxRefererHeaderLength", 4096};
 
-const base::Feature kEnforceTLS13Downgrade{"EnforceTLS13Downgrade",
-                                           base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kEnableTLS13EarlyData{"EnableTLS13EarlyData",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/net/base/features.h b/net/base/features.h
index e42a34f1..58c80c4 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -22,13 +22,6 @@
 NET_EXPORT extern const base::Feature kCapRefererHeaderLength;
 NET_EXPORT extern const base::FeatureParam<int> kMaxRefererHeaderLength;
 
-// Enables the additional TLS 1.3 server-random-based downgrade protection
-// described in https://tools.ietf.org/html/rfc8446#section-4.1.3
-//
-// This is a MUST-level requirement of TLS 1.3, but has compatibility issues
-// with some buggy non-compliant TLS-terminating proxies.
-NET_EXPORT extern const base::Feature kEnforceTLS13Downgrade;
-
 // Enables TLS 1.3 early data.
 NET_EXPORT extern const base::Feature kEnableTLS13EarlyData;
 
diff --git a/net/base/load_flags_list.h b/net/base/load_flags_list.h
index ed457067..6ba0990 100644
--- a/net/base/load_flags_list.h
+++ b/net/base/load_flags_list.h
@@ -79,22 +79,17 @@
 // request. Overrides socket limits. Must always be used with MAXIMUM_PRIORITY.
 LOAD_FLAG(IGNORE_LIMITS, 1 << 12)
 
-// Indicates that the operation is somewhat likely to be due to an
-// explicit user action. This can be used as a hint to treat the
-// request with higher priority.
-LOAD_FLAG(MAYBE_USER_GESTURE, 1 << 13)
-
 // Indicates that the username:password portion of the URL should not
 // be honored, but that other forms of authority may be used.
-LOAD_FLAG(DO_NOT_USE_EMBEDDED_IDENTITY, 1 << 14)
+LOAD_FLAG(DO_NOT_USE_EMBEDDED_IDENTITY, 1 << 13)
 
 // Indicates that this request is not to be migrated to a cellular network when
 // QUIC connection migration is enabled.
-LOAD_FLAG(DISABLE_CONNECTION_MIGRATION_TO_CELLULAR, 1 << 15)
+LOAD_FLAG(DISABLE_CONNECTION_MIGRATION_TO_CELLULAR, 1 << 14)
 
 // Indicates that the cache should not check that the request matches the
 // response's vary header.
-LOAD_FLAG(SKIP_VARY_CHECK, 1 << 16)
+LOAD_FLAG(SKIP_VARY_CHECK, 1 << 15)
 
 // The creator of this URLRequest wishes to receive stale responses when allowed
 // by the "Cache-Control: stale-while-revalidate" directive and is able to issue
@@ -104,16 +99,16 @@
 // resource by issuing a new request without this flag set. If the revalidation
 // does not complete in 60 seconds, the cache treat the stale resource as
 // invalid, as it did not specify stale-while-revalidate.
-LOAD_FLAG(SUPPORT_ASYNC_REVALIDATION, 1 << 17)
+LOAD_FLAG(SUPPORT_ASYNC_REVALIDATION, 1 << 16)
 
 // Indicates that a prefetch request's cached response should be restricted in
 // in terms of reuse. The cached response can only be reused by requests with
 // the LOAD_CAN_USE_RESTRICTED_PREFETCH load flag.
-LOAD_FLAG(RESTRICTED_PREFETCH, 1 << 18)
+LOAD_FLAG(RESTRICTED_PREFETCH, 1 << 17)
 
 // This flag must be set on requests that are allowed to reuse cache entries
 // that are marked as RESTRICTED_PREFETCH. Requests without this flag cannot
 // reuse restricted prefetch responses in the cache. Restricted response reuse
 // is considered privileged, and therefore this flag must only be set from a
 // trusted process.
-LOAD_FLAG(CAN_USE_RESTRICTED_PREFETCH, 1 << 19)
+LOAD_FLAG(CAN_USE_RESTRICTED_PREFETCH, 1 << 18)
diff --git a/net/base/net_errors.h b/net/base/net_errors.h
index f24540a..27d8f66 100644
--- a/net/base/net_errors.h
+++ b/net/base/net_errors.h
@@ -38,7 +38,8 @@
 NET_EXPORT std::string ExtendedErrorToString(int error,
                                              int extended_error_code);
 
-// Returns true if |error| is a certificate error code.
+// Returns true if |error| is a certificate error code. Note this does not
+// include errors for client certificates.
 NET_EXPORT bool IsCertificateError(int error);
 
 // Returns true if |error| is a client certificate authentication error. This
diff --git a/net/base/net_errors_unittest.cc b/net/base/net_errors_unittest.cc
new file mode 100644
index 0000000..5d9e2f7
--- /dev/null
+++ b/net/base/net_errors_unittest.cc
@@ -0,0 +1,79 @@
+// 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 "net/base/net_errors.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+TEST(NetErrorsTest, IsCertificateError) {
+  // Positive tests.
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_AUTHORITY_INVALID));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_COMMON_NAME_INVALID));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_CONTAINS_ERRORS));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_DATE_INVALID));
+  EXPECT_TRUE(IsCertificateError(ERR_CERTIFICATE_TRANSPARENCY_REQUIRED));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_INVALID));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_NAME_CONSTRAINT_VIOLATION));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_NON_UNIQUE_NAME));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_NO_REVOCATION_MECHANISM));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_REVOKED));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_SYMANTEC_LEGACY));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_UNABLE_TO_CHECK_REVOCATION));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_VALIDITY_TOO_LONG));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_WEAK_KEY));
+  EXPECT_TRUE(IsCertificateError(ERR_CERT_WEAK_SIGNATURE_ALGORITHM));
+  EXPECT_TRUE(IsCertificateError(ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN));
+
+  // Negative tests.
+  EXPECT_FALSE(IsCertificateError(ERR_SSL_PROTOCOL_ERROR));
+  EXPECT_FALSE(IsCertificateError(ERR_SSL_KEY_USAGE_INCOMPATIBLE));
+  EXPECT_FALSE(
+      IsCertificateError(ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED));
+  EXPECT_FALSE(IsCertificateError(ERR_QUIC_CERT_ROOT_NOT_KNOWN));
+  EXPECT_FALSE(IsCertificateError(ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY));
+  EXPECT_FALSE(IsCertificateError(ERR_FAILED));
+  EXPECT_FALSE(IsCertificateError(OK));
+
+  // Trigger a failure whenever ERR_CERT_END is changed, forcing developers to
+  // update this test.
+  EXPECT_EQ(ERR_CERT_END, -217)
+      << "It looks like you added a new certificate error code ("
+      << ErrorToString(ERR_CERT_END + 1)
+      << ").\n"
+         "\n"
+         "Because this code is between ERR_CERT_BEGIN and ERR_CERT_END, it "
+         "will be matched by net::IsCertificateError().\n"
+         "\n"
+         " (1) Please add a new test case to "
+         "NetErrorsTest.IsCertificateError()."
+         "\n"
+         " (2) Review the existing consumers of IsCertificateError(). "
+         "//content for instance has specialized handling of "
+         "IsCertificateError() that may need to be updated.";
+}
+
+TEST(NetErrorsTest, IsClientCertificateError) {
+  // Positive tests.
+  EXPECT_TRUE(IsClientCertificateError(ERR_BAD_SSL_CLIENT_AUTH_CERT));
+  EXPECT_TRUE(
+      IsClientCertificateError(ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED));
+  EXPECT_TRUE(
+      IsClientCertificateError(ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY));
+  EXPECT_TRUE(IsClientCertificateError(ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED));
+  EXPECT_TRUE(
+      IsClientCertificateError(ERR_SSL_CLIENT_AUTH_NO_COMMON_ALGORITHMS));
+
+  // Negative tests.
+  EXPECT_FALSE(IsClientCertificateError(ERR_CERT_REVOKED));
+  EXPECT_FALSE(IsClientCertificateError(ERR_SSL_PROTOCOL_ERROR));
+  EXPECT_FALSE(IsClientCertificateError(ERR_CERT_WEAK_KEY));
+}
+
+}  // namespace
+
+}  // namespace net
diff --git a/net/cert/cert_verify_proc_blocklist.inc b/net/cert/cert_verify_proc_blocklist.inc
index 0df8aaa..b4abe89 100644
--- a/net/cert/cert_verify_proc_blocklist.inc
+++ b/net/cert/cert_verify_proc_blocklist.inc
@@ -169,10 +169,6 @@
         {0x9b, 0x8a, 0x93, 0xde, 0xcc, 0xcf, 0xba, 0xfc, 0xf4, 0xd0, 0x4d,
          0x34, 0x42, 0x12, 0x8f, 0xb3, 0x52, 0x18, 0xcf, 0xe4, 0x37, 0xa3,
          0xd8, 0xd0, 0x32, 0x8c, 0x99, 0xf8, 0x90, 0x89, 0xe4, 0x50},
-        // 2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem
-        {0x9c, 0x35, 0x74, 0x7c, 0x3a, 0x53, 0x5c, 0xf2, 0x13, 0xb1, 0x47,
-         0x4e, 0xdb, 0x39, 0x77, 0xf1, 0x38, 0x24, 0x0d, 0x6d, 0xc1, 0xce,
-         0xcd, 0xee, 0x74, 0x11, 0xa8, 0xf1, 0x25, 0x53, 0xb1, 0x3e},
         // 8253da6738b60c5c0bb139c78e045428a0c841272abdcb952f95ff05ed1ab476.pem
         {0x9c, 0x59, 0xa3, 0xcc, 0xae, 0xa4, 0x69, 0x98, 0x42, 0xb0, 0x68,
          0xcf, 0xc5, 0x2c, 0xf9, 0x45, 0xdb, 0x51, 0x98, 0x69, 0x57, 0xc8,
@@ -319,4 +315,8 @@
         {0xfc, 0xd7, 0x6c, 0xca, 0x23, 0x47, 0xe5, 0xcd, 0x5b, 0x39, 0x34,
          0x7f, 0x51, 0xcf, 0x43, 0x65, 0x4b, 0x69, 0xa2, 0xbf, 0xc9, 0x07,
          0x36, 0x70, 0xa6, 0xbe, 0x47, 0xd8, 0x70, 0x1e, 0x6e, 0x0e},
+        // c6910d0ba9eddf593334149fedfe87385f37b625354bb4395c0ae2c8df48e17c.pem
+        {0xc6, 0x91, 0x0d, 0x0b, 0xa9, 0xed, 0xdf, 0x59, 0x33, 0x34, 0x14,
+         0x9f, 0xed, 0xfe, 0x87, 0x38, 0x5f, 0x37, 0xb6, 0x25, 0x35, 0x4b,
+         0xb4, 0x39, 0x5c, 0x0a, 0xe2, 0xc8, 0xdf, 0x48, 0xe1, 0x7c},
 };
diff --git a/net/cookies/cookie_constants.h b/net/cookies/cookie_constants.h
index 8257114..6a58470 100644
--- a/net/cookies/cookie_constants.h
+++ b/net/cookies/cookie_constants.h
@@ -70,13 +70,10 @@
   kMaxValue = kExtended
 };
 
-// What rules to apply when determining when whether access to a particular
-// cookie is allowed.
-// TODO(crbug.com/978172): Machinery to read the content setting and set the
-// appropriate CookieAccessSemantics on the cookie (will be added as a new
-// metadata field of CanonicalCookie).
+// What rules to apply when determining whether access to a particular cookie is
+// allowed.
 enum class CookieAccessSemantics {
-  // Has not been checked yet.
+  // Has not been checked yet or there is no way to check.
   UNKNOWN = -1,
   // Has been checked and the cookie should *not* be subject to legacy access
   // rules.
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 81b6395a..e317102 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -387,7 +387,7 @@
 void CookieMonster::SetAllCookiesAsync(const CookieList& list,
                                        SetCookiesCallback callback) {
   DoCookieCallback(base::BindOnce(
-      // base::Unretained is safe as DoCookieCallbackForURL stores
+      // base::Unretained is safe as DoCookieCallback stores
       // the callback on |*this|, so the callback will not outlive
       // the object.
       &CookieMonster::SetAllCookies, base::Unretained(this), list,
@@ -404,7 +404,7 @@
   std::string domain = cookie->Domain();
   DoCookieCallbackForHostOrDomain(
       base::BindOnce(
-          // base::Unretained is safe as DoCookieCallbackForURL stores
+          // base::Unretained is safe as DoCookieCallbackForHostOrDomain stores
           // the callback on |*this|, so the callback will not outlive
           // the object.
           &CookieMonster::SetCanonicalCookie, base::Unretained(this),
@@ -429,17 +429,28 @@
 
 void CookieMonster::GetAllCookiesAsync(GetAllCookiesCallback callback) {
   DoCookieCallback(base::BindOnce(
-      // base::Unretained is safe as DoCookieCallbackForURL stores
+      // base::Unretained is safe as DoCookieCallback stores
       // the callback on |*this|, so the callback will not outlive
       // the object.
       &CookieMonster::GetAllCookies, base::Unretained(this),
       std::move(callback)));
 }
 
+void CookieMonster::GetAllCookiesWithAccessSemanticsAsync(
+    GetAllCookiesWithAccessSemanticsCallback callback) {
+  DoCookieCallback(base::BindOnce(
+      // base::Unretained is safe as DoCookieCallback stores
+      // the callback on |*this|, so the callback will not outlive
+      // the object.
+      &CookieMonster::GetAllCookies, base::Unretained(this),
+      base::BindOnce(&CookieMonster::AttachAccessSemanticsListForCookieList,
+                     base::Unretained(this), std::move(callback))));
+}
+
 void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
                                                DeleteCallback callback) {
   DoCookieCallback(base::BindOnce(
-      // base::Unretained is safe as DoCookieCallbackForURL stores
+      // base::Unretained is safe as DoCookieCallback stores
       // the callback on |*this|, so the callback will not outlive
       // the object.
       &CookieMonster::DeleteCanonicalCookie, base::Unretained(this), cookie,
@@ -450,7 +461,7 @@
     const TimeRange& creation_range,
     DeleteCallback callback) {
   DoCookieCallback(base::BindOnce(
-      // base::Unretained is safe as DoCookieCallbackForURL stores
+      // base::Unretained is safe as DoCookieCallback stores
       // the callback on |*this|, so the callback will not outlive
       // the object.
       &CookieMonster::DeleteAllCreatedInTimeRange, base::Unretained(this),
@@ -460,7 +471,7 @@
 void CookieMonster::DeleteAllMatchingInfoAsync(CookieDeletionInfo delete_info,
                                                DeleteCallback callback) {
   DoCookieCallback(base::BindOnce(
-      // base::Unretained is safe as DoCookieCallbackForURL stores
+      // base::Unretained is safe as DoCookieCallback stores
       // the callback on |*this|, so the callback will not outlive
       // the object.
       &CookieMonster::DeleteAllMatchingInfo, base::Unretained(this),
@@ -470,7 +481,7 @@
 void CookieMonster::DeleteSessionCookiesAsync(
     CookieStore::DeleteCallback callback) {
   DoCookieCallback(base::BindOnce(
-      // base::Unretained is safe as DoCookieCallbackForURL stores
+      // base::Unretained is safe as DoCookieCallback stores
       // the callback on |*this|, so the callback will not outlive
       // the object.
       &CookieMonster::DeleteSessionCookies, base::Unretained(this),
@@ -588,6 +599,17 @@
   MaybeRunCookieCallback(std::move(callback), cookie_list);
 }
 
+void CookieMonster::AttachAccessSemanticsListForCookieList(
+    GetAllCookiesWithAccessSemanticsCallback callback,
+    const CookieList& cookie_list) {
+  std::vector<CookieAccessSemantics> access_semantics_list;
+  for (const CanonicalCookie& cookie : cookie_list) {
+    access_semantics_list.push_back(GetAccessSemanticsForCookie(cookie));
+  }
+  MaybeRunCookieCallback(std::move(callback), cookie_list,
+                         access_semantics_list);
+}
+
 void CookieMonster::GetCookieListWithOptions(const GURL& url,
                                              const CookieOptions& options,
                                              GetCookieListCallback callback) {
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index de36d79..66ad270b 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -165,6 +165,8 @@
                                      const CookieOptions& options,
                                      GetCookieListCallback callback) override;
   void GetAllCookiesAsync(GetAllCookiesCallback callback) override;
+  void GetAllCookiesWithAccessSemanticsAsync(
+      GetAllCookiesWithAccessSemanticsCallback callback) override;
   void DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
                                   DeleteCallback callback) override;
   void DeleteAllCreatedInTimeRangeAsync(
@@ -354,6 +356,10 @@
 
   void GetAllCookies(GetAllCookiesCallback callback);
 
+  void AttachAccessSemanticsListForCookieList(
+      GetAllCookiesWithAccessSemanticsCallback callback,
+      const CookieList& cookie_list);
+
   void GetCookieListWithOptions(const GURL& url,
                                 const CookieOptions& options,
                                 GetCookieListCallback callback);
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 6908bbd9438..db86678 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -92,6 +92,7 @@
   static const bool has_exact_change_cause = true;
   static const bool has_exact_change_ordering = true;
   static const int creation_time_granularity_in_ms = 0;
+  static const bool supports_cookie_access_semantics = true;
 };
 
 INSTANTIATE_TYPED_TEST_SUITE_P(CookieMonster,
diff --git a/net/cookies/cookie_store.cc b/net/cookies/cookie_store.cc
index 0556a07..6f7b1ca 100644
--- a/net/cookies/cookie_store.cc
+++ b/net/cookies/cookie_store.cc
@@ -13,6 +13,24 @@
 
 CookieStore::~CookieStore() = default;
 
+// Default implementation which returns a default vector of UNKNOWN
+// CookieAccessSemantics.
+void CookieStore::GetAllCookiesWithAccessSemanticsAsync(
+    GetAllCookiesWithAccessSemanticsCallback callback) {
+  GetAllCookiesCallback adapted_callback = base::BindOnce(
+      [](CookieStore::GetAllCookiesWithAccessSemanticsCallback
+             original_callback,
+         const CookieList& cookies) {
+        std::vector<CookieAccessSemantics> default_access_semantics_list;
+        default_access_semantics_list.assign(cookies.size(),
+                                             CookieAccessSemantics::UNKNOWN);
+        std::move(original_callback)
+            .Run(cookies, default_access_semantics_list);
+      },
+      std::move(callback));
+  GetAllCookiesAsync(std::move(adapted_callback));
+}
+
 void CookieStore::DeleteAllAsync(DeleteCallback callback) {
   DeleteAllCreatedInTimeRangeAsync(CookieDeletionInfo::TimeRange(),
                                    std::move(callback));
diff --git a/net/cookies/cookie_store.h b/net/cookies/cookie_store.h
index 102428f..ebec5df 100644
--- a/net/cookies/cookie_store.h
+++ b/net/cookies/cookie_store.h
@@ -49,6 +49,10 @@
                               const CookieStatusList& excluded_list)>;
   using GetAllCookiesCallback =
       base::OnceCallback<void(const CookieList& cookies)>;
+  // |access_semantics_list| is guaranteed to the same length as |cookies|.
+  using GetAllCookiesWithAccessSemanticsCallback = base::OnceCallback<void(
+      const CookieList& cookies,
+      const std::vector<CookieAccessSemantics>& access_semantics_list)>;
   using SetCookiesCallback =
       base::OnceCallback<void(CanonicalCookie::CookieInclusionStatus status)>;
   using DeleteCallback = base::OnceCallback<void(uint32_t num_deleted)>;
@@ -84,6 +88,18 @@
   // longest path, then by earliest creation date.
   virtual void GetAllCookiesAsync(GetAllCookiesCallback callback) = 0;
 
+  // Returns all the cookies, for use in management UI, etc. This does not mark
+  // the cookies as having been accessed. The returned cookies are ordered by
+  // longest path, then by earliest creation date.
+  // Additionally returns a vector of CookieAccessSemantics values for the
+  // returned cookies, which will be the same length as the vector of returned
+  // cookies. This vector will either contain all CookieAccessSemantics::UNKNOWN
+  // (if the default implementation is used), or each entry in the
+  // vector of CookieAccessSemantics will indicate the access semantics
+  // applicable to the cookie at the same index in the returned CookieList.
+  virtual void GetAllCookiesWithAccessSemanticsAsync(
+      GetAllCookiesWithAccessSemanticsCallback callback);
+
   // Deletes one specific cookie. |cookie| must have been returned by a previous
   // query on this CookieStore. Invokes |callback| with 1 if a cookie was
   // deleted, 0 otherwise.
diff --git a/net/cookies/cookie_store_test_callbacks.cc b/net/cookies/cookie_store_test_callbacks.cc
index dff2abe..87ab3aee 100644
--- a/net/cookies/cookie_store_test_callbacks.cc
+++ b/net/cookies/cookie_store_test_callbacks.cc
@@ -80,4 +80,21 @@
   CallbackEpilogue();
 }
 
+GetAllCookiesWithAccessSemanticsCallback::
+    GetAllCookiesWithAccessSemanticsCallback() = default;
+GetAllCookiesWithAccessSemanticsCallback::
+    GetAllCookiesWithAccessSemanticsCallback(base::Thread* run_in_thread)
+    : CookieCallback(run_in_thread) {}
+
+GetAllCookiesWithAccessSemanticsCallback::
+    ~GetAllCookiesWithAccessSemanticsCallback() = default;
+
+void GetAllCookiesWithAccessSemanticsCallback::Run(
+    const CookieList& cookies,
+    const std::vector<CookieAccessSemantics>& access_semantics_list) {
+  cookies_ = cookies;
+  access_semantics_list_ = access_semantics_list;
+  CallbackEpilogue();
+}
+
 }  // namespace net
diff --git a/net/cookies/cookie_store_test_callbacks.h b/net/cookies/cookie_store_test_callbacks.h
index af7f6f2..54b00b5 100644
--- a/net/cookies/cookie_store_test_callbacks.h
+++ b/net/cookies/cookie_store_test_callbacks.h
@@ -13,6 +13,7 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_store.h"
 
 namespace base {
@@ -151,6 +152,36 @@
   CookieList cookies_;
 };
 
+class GetAllCookiesWithAccessSemanticsCallback : public CookieCallback {
+ public:
+  GetAllCookiesWithAccessSemanticsCallback();
+  explicit GetAllCookiesWithAccessSemanticsCallback(
+      base::Thread* run_in_thread);
+
+  ~GetAllCookiesWithAccessSemanticsCallback();
+
+  void Run(const CookieList& cookies,
+           const std::vector<CookieAccessSemantics>& access_semantics_list);
+
+  // Makes a callback that will invoke Run. Assumes that |this| will be kept
+  // alive till the time the callback is used.
+  base::OnceCallback<void(const CookieList&,
+                          const std::vector<CookieAccessSemantics>&)>
+  MakeCallback() {
+    return base::BindOnce(&GetAllCookiesWithAccessSemanticsCallback::Run,
+                          base::Unretained(this));
+  }
+
+  const CookieList& cookies() { return cookies_; }
+  const std::vector<CookieAccessSemantics>& access_semantics_list() {
+    return access_semantics_list_;
+  }
+
+ private:
+  CookieList cookies_;
+  std::vector<CookieAccessSemantics> access_semantics_list_;
+};
+
 }  // namespace net
 
 #endif  // NET_COOKIES_COOKIE_STORE_TEST_CALLBACKS_H_
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 8fe683929..d91026b 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -24,6 +24,7 @@
 #include "net/cookies/cookie_store.h"
 #include "net/cookies/cookie_store_test_callbacks.h"
 #include "net/cookies/cookie_store_test_helpers.h"
+#include "net/cookies/test_cookie_access_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -101,6 +102,11 @@
 //   // Time to wait between two cookie insertions to ensure that cookies have
 //   // different creation times.
 //   static const int creation_time_granularity_in_ms;
+//
+//   // The cookie store supports setting a CookieAccessDelegate and using it to
+//   // get the access semantics for each cookie via
+//   // CookieStore::GetAllCookiesWithAccessSemanticsAsync().
+//   static const bool supports_cookie_access_semantics;
 // };
 
 template <class CookieStoreTestTraits>
@@ -1661,6 +1667,58 @@
   ASSERT_TRUE(++it == cookies.end());
 }
 
+TYPED_TEST_P(CookieStoreTest, GetAllCookiesWithAccessSemanticsAsync) {
+  CookieStore* cs = this->GetCookieStore();
+  auto access_delegate = std::make_unique<TestCookieAccessDelegate>();
+  TestCookieAccessDelegate* test_delegate = access_delegate.get();
+  // if !supports_cookie_access_semantics, setting a delegate here will do
+  // nothing.
+  cs->SetCookieAccessDelegate(std::move(access_delegate));
+
+  test_delegate->SetExpectationForCookieDomain("domain1.test",
+                                               CookieAccessSemantics::LEGACY);
+  test_delegate->SetExpectationForCookieDomain(
+      "domain2.test", CookieAccessSemantics::NONLEGACY);
+  test_delegate->SetExpectationForCookieDomain("domain3.test",
+                                               CookieAccessSemantics::UNKNOWN);
+
+  this->CreateAndSetCookie(cs, GURL("http://domain1.test"), "cookie=1",
+                           CookieOptions::MakeAllInclusive());
+  this->CreateAndSetCookie(cs, GURL("http://domain2.test"), "cookie=1",
+                           CookieOptions::MakeAllInclusive());
+  this->CreateAndSetCookie(cs, GURL("http://domain3.test"), "cookie=1",
+                           CookieOptions::MakeAllInclusive());
+  this->CreateAndSetCookie(cs, GURL("http://domain4.test"), "cookie=1",
+                           CookieOptions::MakeAllInclusive());
+
+  GetAllCookiesWithAccessSemanticsCallback callback;
+  cs->GetAllCookiesWithAccessSemanticsAsync(callback.MakeCallback());
+  callback.WaitUntilDone();
+  EXPECT_TRUE(callback.was_run());
+
+  EXPECT_EQ(callback.cookies().size(), callback.access_semantics_list().size());
+  EXPECT_EQ(4u, callback.access_semantics_list().size());
+  EXPECT_EQ("domain1.test", callback.cookies()[0].Domain());
+  EXPECT_EQ("domain2.test", callback.cookies()[1].Domain());
+  EXPECT_EQ("domain3.test", callback.cookies()[2].Domain());
+  EXPECT_EQ("domain4.test", callback.cookies()[3].Domain());
+
+  if (!TypeParam::supports_cookie_access_semantics) {
+    for (CookieAccessSemantics semantics : callback.access_semantics_list()) {
+      EXPECT_EQ(CookieAccessSemantics::UNKNOWN, semantics);
+    }
+  } else {
+    EXPECT_EQ(CookieAccessSemantics::LEGACY,
+              callback.access_semantics_list()[0]);
+    EXPECT_EQ(CookieAccessSemantics::NONLEGACY,
+              callback.access_semantics_list()[1]);
+    EXPECT_EQ(CookieAccessSemantics::UNKNOWN,
+              callback.access_semantics_list()[2]);
+    EXPECT_EQ(CookieAccessSemantics::UNKNOWN,
+              callback.access_semantics_list()[3]);
+  }
+}
+
 TYPED_TEST_P(CookieStoreTest, DeleteCanonicalCookieAsync) {
   CookieStore* cs = this->GetCookieStore();
 
@@ -1756,6 +1814,7 @@
                             EmptyName,
                             CookieOrdering,
                             GetAllCookiesAsync,
+                            GetAllCookiesWithAccessSemanticsAsync,
                             DeleteCanonicalCookieAsync,
                             DeleteSessionCookie);
 
diff --git a/net/data/ssl/blocklist/2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem b/net/data/ssl/blocklist/2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem
deleted file mode 100644
index 03544516..0000000
--- a/net/data/ssl/blocklist/2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem
+++ /dev/null
@@ -1,156 +0,0 @@
-Certificate:
-    Data:
-        Version: 3 (0x2)
-        Serial Number:
-            01:af:1e:fb:dd:5e:ae:09:52:32:0b:24:fe:6b:55:68
-    Signature Algorithm: sha256WithRSAEncryption
-        Issuer: C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
-        Validity
-            Not Before: Sep  2 00:00:00 2016 GMT
-            Not After : Sep 11 12:00:00 2019 GMT
-        Subject: C = US, ST = California, L = Walnut Creek, O = Lucas Garron, CN = revoked.badssl.com
-        Subject Public Key Info:
-            Public Key Algorithm: rsaEncryption
-                Public-Key: (2048 bit)
-                Modulus:
-                    00:c7:31:65:e4:55:cf:69:90:9f:6e:1f:d8:6a:13:
-                    7e:74:bf:13:3a:54:64:0f:74:24:3d:dc:60:b8:a7:
-                    45:01:b7:c8:6a:03:ac:64:4a:65:f0:7c:81:81:83:
-                    0a:d9:dd:31:20:82:48:a6:33:63:ee:2b:74:ea:b4:
-                    e6:c7:1c:b2:5e:e4:28:3a:7a:3d:20:19:03:b7:15:
-                    3f:4f:c9:26:ec:b7:cb:bf:48:6e:5f:34:70:56:c4:
-                    86:c7:e3:52:9a:21:33:2f:10:13:f3:25:0c:1e:94:
-                    35:2e:e8:d0:d1:b5:a0:77:40:91:2e:e9:ba:f8:ff:
-                    4e:f5:fb:f2:7a:04:a7:e6:c6:ce:3f:0f:10:18:32:
-                    c8:06:bc:15:b3:be:69:ac:75:7d:42:a0:8c:2e:c3:
-                    ac:e1:20:4f:1e:36:9c:9a:2e:a2:fd:79:80:b6:62:
-                    f8:c0:b2:03:a9:29:50:cc:d5:25:8a:33:5e:e0:78:
-                    13:18:c0:80:17:09:95:bd:a2:fe:92:15:07:20:7a:
-                    81:ce:db:0e:81:29:89:d4:c8:ec:b3:b3:79:0e:f2:
-                    ce:25:e7:ee:be:21:7d:af:0c:13:94:29:de:35:9a:
-                    1e:d8:84:18:5a:5c:1a:94:82:ce:9a:61:d6:9d:ec:
-                    f8:ee:ad:3f:09:5b:73:ec:a2:9b:fa:dc:62:f1:58:
-                    1f:7d
-                Exponent: 65537 (0x10001)
-        X509v3 extensions:
-            X509v3 Authority Key Identifier: 
-                keyid:0F:80:61:1C:82:31:61:D5:2F:28:E7:8D:46:38:B4:2C:E1:C6:D9:E2
-
-            X509v3 Subject Key Identifier: 
-                F4:48:7D:07:45:1A:32:07:90:91:AC:05:B8:9F:A9:11:F0:7E:11:36
-            X509v3 Subject Alternative Name: 
-                DNS:revoked.badssl.com
-            X509v3 Key Usage: critical
-                Digital Signature, Key Encipherment
-            X509v3 Extended Key Usage: 
-                TLS Web Server Authentication, TLS Web Client Authentication
-            X509v3 CRL Distribution Points: 
-
-                Full Name:
-                  URI:http://crl3.digicert.com/ssca-sha2-g5.crl
-
-                Full Name:
-                  URI:http://crl4.digicert.com/ssca-sha2-g5.crl
-
-            X509v3 Certificate Policies: 
-                Policy: 2.16.840.1.114412.1.1
-                  CPS: https://www.digicert.com/CPS
-                Policy: 2.23.140.1.2.3
-
-            Authority Information Access: 
-                OCSP - URI:http://ocsp.digicert.com
-                CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt
-
-            X509v3 Basic Constraints: critical
-                CA:FALSE
-            CT Precertificate SCTs: 
-                Signed Certificate Timestamp:
-                    Version   : v1 (0x0)
-                    Log ID    : A4:B9:09:90:B4:18:58:14:87:BB:13:A2:CC:67:70:0A:
-                                3C:35:98:04:F9:1B:DF:B8:E3:77:CD:0E:C8:0D:DC:10
-                    Timestamp : Sep  2 20:40:03.802 2016 GMT
-                    Extensions: none
-                    Signature : ecdsa-with-SHA256
-                                30:44:02:20:3F:6C:A8:F5:C4:7C:01:4C:C3:5A:28:27:
-                                50:47:63:D9:AC:E1:BE:2D:BF:87:78:CB:3A:80:97:24:
-                                74:CD:16:F7:02:20:71:FF:93:A2:B5:54:7E:7F:53:45:
-                                7F:59:5A:60:18:21:5C:AB:7D:1F:08:B2:54:A0:B3:C4:
-                                88:A5:83:D2:63:55
-                Signed Certificate Timestamp:
-                    Version   : v1 (0x0)
-                    Log ID    : 68:F6:98:F8:1F:64:82:BE:3A:8C:EE:B9:28:1D:4C:FC:
-                                71:51:5D:67:93:D4:44:D1:0A:67:AC:BB:4F:4F:FB:C4
-                    Timestamp : Sep  2 20:40:03.745 2016 GMT
-                    Extensions: none
-                    Signature : ecdsa-with-SHA256
-                                30:46:02:21:00:FE:59:97:22:4C:6C:0F:39:05:D9:E4:
-                                CA:7E:3B:D3:B3:47:1B:61:72:B6:3A:4F:D6:F2:A3:57:
-                                49:48:4F:6A:6D:02:21:00:8F:14:1B:3C:1B:89:A3:1D:
-                                70:EC:D4:D7:11:BC:F9:0B:3C:60:AC:8C:84:73:24:6B:
-                                0E:37:6E:53:7F:9D:7F:34
-                Signed Certificate Timestamp:
-                    Version   : v1 (0x0)
-                    Log ID    : 56:14:06:9A:2F:D7:C2:EC:D3:F5:E1:BD:44:B2:3E:C7:
-                                46:76:B9:BC:99:11:5C:C0:EF:94:98:55:D6:89:D0:DD
-                    Timestamp : Sep  2 20:40:03.967 2016 GMT
-                    Extensions: none
-                    Signature : ecdsa-with-SHA256
-                                30:45:02:20:0E:BF:53:59:17:0C:EC:66:0C:5E:87:BB:
-                                8F:5F:B6:76:86:F2:5C:FC:BC:A8:B9:C0:DF:BC:1A:3B:
-                                EE:11:F2:D0:02:21:00:87:25:39:E4:32:99:48:CA:20:
-                                1B:13:96:1D:C3:2C:98:6B:1B:C0:CC:E5:67:22:BD:92:
-                                14:E9:68:CD:95:82:32
-    Signature Algorithm: sha256WithRSAEncryption
-         5a:a0:49:88:ad:60:1f:08:53:4c:d9:b8:dc:f5:40:41:ad:ef:
-         c8:7b:01:3b:13:70:44:99:f6:5c:23:46:f7:3a:c8:7d:c9:21:
-         ad:3a:49:45:82:1e:5d:3b:1e:9b:6a:0a:3e:61:2d:f6:b1:99:
-         74:2f:91:f9:d5:f1:9f:ae:74:26:8b:3c:a7:8c:be:28:fe:ac:
-         3b:70:ae:08:56:71:ac:55:7c:40:89:02:2d:61:2a:fd:54:72:
-         bf:1a:5c:70:19:90:15:a4:76:a0:7f:56:1c:c1:f0:8d:5e:99:
-         3d:83:41:54:68:e5:62:c1:5a:a2:64:8c:01:64:7a:23:b9:3f:
-         bf:22:cf:1f:c0:47:80:1f:94:d5:f2:30:84:fb:07:02:fa:5b:
-         a0:ba:09:04:98:4e:f3:25:56:4c:c4:7e:e0:27:d8:e8:32:8f:
-         b3:3c:5a:92:4b:c0:77:2d:b0:e5:ae:1f:af:1d:7f:21:9c:65:
-         26:be:0c:ba:e8:0d:c1:d2:67:b4:b9:33:d1:4a:ee:fc:b8:af:
-         03:5b:c8:3e:bc:fa:09:9d:04:ce:3e:a6:b5:c4:74:3b:31:7a:
-         f3:2c:42:b3:c7:73:db:aa:75:2e:8d:8a:9e:79:33:be:d7:b6:
-         14:9b:26:ab:7b:9e:14:b3:55:e6:4b:bb:86:94:11:74:02:35:
-         b4:52:70:9b
------BEGIN CERTIFICATE-----
-MIIGoTCCBYmgAwIBAgIQAa8e+91erglSMgsk/mtVaDANBgkqhkiG9w0BAQsFADBN
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E
-aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTYwOTAyMDAwMDAwWhcN
-MTkwOTExMTIwMDAwWjBtMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5p
-YTEVMBMGA1UEBxMMV2FsbnV0IENyZWVrMRUwEwYDVQQKEwxMdWNhcyBHYXJyb24x
-GzAZBgNVBAMTEnJldm9rZWQuYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAMcxZeRVz2mQn24f2GoTfnS/EzpUZA90JD3cYLinRQG3yGoD
-rGRKZfB8gYGDCtndMSCCSKYzY+4rdOq05sccsl7kKDp6PSAZA7cVP0/JJuy3y79I
-bl80cFbEhsfjUpohMy8QE/MlDB6UNS7o0NG1oHdAkS7puvj/TvX78noEp+bGzj8P
-EBgyyAa8FbO+aax1fUKgjC7DrOEgTx42nJouov15gLZi+MCyA6kpUMzVJYozXuB4
-ExjAgBcJlb2i/pIVByB6gc7bDoEpidTI7LOzeQ7yziXn7r4hfa8ME5Qp3jWaHtiE
-GFpcGpSCzpph1p3s+O6tPwlbc+yim/rcYvFYH30CAwEAAaOCA1swggNXMB8GA1Ud
-IwQYMBaAFA+AYRyCMWHVLyjnjUY4tCzhxtniMB0GA1UdDgQWBBT0SH0HRRoyB5CR
-rAW4n6kR8H4RNjAdBgNVHREEFjAUghJyZXZva2VkLmJhZHNzbC5jb20wDgYDVR0P
-AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8E
-ZDBiMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc1
-LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1n
-NS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0
-cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgMwfAYIKwYBBQUHAQEE
-cDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYB
-BQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJT
-ZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAX4GCisGAQQB1nkCBAIE
-ggFuBIIBagFoAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFW
-7KE32gAABAMARjBEAiA/bKj1xHwBTMNaKCdQR2PZrOG+Lb+HeMs6gJckdM0W9wIg
-cf+TorVUfn9TRX9ZWmAYIVyrfR8IslSgs8SIpYPSY1UAdwBo9pj4H2SCvjqM7rko
-HUz8cVFdZ5PURNEKZ6y7T0/7xAAAAVbsoTehAAAEAwBIMEYCIQD+WZciTGwPOQXZ
-5Mp+O9OzRxthcrY6T9byo1dJSE9qbQIhAI8UGzwbiaMdcOzU1xG8+Qs8YKyMhHMk
-aw43blN/nX80AHYAVhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ0N0AAAFW
-7KE4fwAABAMARzBFAiAOv1NZFwzsZgxeh7uPX7Z2hvJc/LyoucDfvBo77hHy0AIh
-AIclOeQymUjKIBsTlh3DLJhrG8DM5WcivZIU6WjNlYIyMA0GCSqGSIb3DQEBCwUA
-A4IBAQBaoEmIrWAfCFNM2bjc9UBBre/IewE7E3BEmfZcI0b3Osh9ySGtOklFgh5d
-Ox6bago+YS32sZl0L5H51fGfrnQmizynjL4o/qw7cK4IVnGsVXxAiQItYSr9VHK/
-GlxwGZAVpHagf1YcwfCNXpk9g0FUaOViwVqiZIwBZHojuT+/Is8fwEeAH5TV8jCE
-+wcC+lugugkEmE7zJVZMxH7gJ9joMo+zPFqSS8B3LbDlrh+vHX8hnGUmvgy66A3B
-0me0uTPRSu78uK8DW8g+vPoJnQTOPqa1xHQ7MXrzLEKzx3PbqnUujYqeeTO+17YU
-myare54Us1XmS7uGlBF0AjW0UnCb
------END CERTIFICATE-----
diff --git a/net/data/ssl/blocklist/README.md b/net/data/ssl/blocklist/README.md
index 84f46f2..11afdd0 100644
--- a/net/data/ssl/blocklist/README.md
+++ b/net/data/ssl/blocklist/README.md
@@ -285,7 +285,7 @@
 
 ### revoked.badssl.com
 
-  * [2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem](2e0f66a9f9e764c33008482058fe0d92fc0ec0b122fbe994ed7bf6463668cdd4.pem)
+  * [c6910d0ba9eddf593334149fedfe87385f37b625354bb4395c0ae2c8df48e17c.pem](c6910d0ba9eddf593334149fedfe87385f37b625354bb4395c0ae2c8df48e17c.pem)
 
 ### revoked.grc.com
 
@@ -302,7 +302,7 @@
 
 ### Symantec
 
-For details, see <https://bugzilla.mozilla.org/show_bug.cgi?id=966060> 
+For details, see <https://bugzilla.mozilla.org/show_bug.cgi?id=966060>
 
 These three intermediate certificates were retired by Symantec, and
 blocked for robustness at their request.
diff --git a/net/data/ssl/blocklist/c6910d0ba9eddf593334149fedfe87385f37b625354bb4395c0ae2c8df48e17c.pem b/net/data/ssl/blocklist/c6910d0ba9eddf593334149fedfe87385f37b625354bb4395c0ae2c8df48e17c.pem
new file mode 100644
index 0000000..9f1647a
--- /dev/null
+++ b/net/data/ssl/blocklist/c6910d0ba9eddf593334149fedfe87385f37b625354bb4395c0ae2c8df48e17c.pem
@@ -0,0 +1,157 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            03:71:b5:8a:86:f6:ce:9c:3e:cb:7b:f4:2f:92:08:fc
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
+        Validity
+            Not Before: Oct  4 00:00:00 2019 GMT
+            Not After : Oct  8 12:00:00 2021 GMT
+        Subject: C = US, ST = California, L = Walnut Creek, O = Lucas Garron Torres, CN = revoked.badssl.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                RSA Public-Key: (2048 bit)
+                Modulus:
+                    00:b4:2e:39:27:f6:76:56:fa:f9:82:2f:a0:2d:f2:
+                    d0:32:19:99:55:dc:89:44:96:f7:73:23:af:f7:a4:
+                    5e:3e:74:bf:59:79:cd:5f:0b:e7:8f:fb:03:19:bf:
+                    8f:9e:63:d2:ff:02:7c:76:fe:16:e9:02:fc:86:90:
+                    5f:98:5c:d6:9a:ba:2e:95:e8:d8:a5:c5:f4:9c:9d:
+                    a7:b9:de:b8:4a:71:62:fd:2a:28:7d:02:af:46:d6:
+                    0d:1d:71:61:d9:4c:db:97:15:00:34:f4:53:81:bc:
+                    8e:94:39:de:d8:be:42:7f:24:ea:02:53:c6:5b:80:
+                    3e:11:2e:d2:d9:0b:6d:18:86:ac:21:d6:77:d9:48:
+                    a9:4f:a3:5b:1d:f3:a5:36:64:d6:4d:1f:46:b7:f3:
+                    35:10:f5:7b:45:3a:dd:a4:18:db:bd:a3:4e:c3:10:
+                    9b:19:84:e5:96:95:9b:5d:e7:56:72:ab:27:85:69:
+                    14:dc:e1:5e:36:cd:69:ca:73:c0:82:07:7d:fc:7e:
+                    8d:2e:fb:cb:c9:79:2e:97:36:43:0f:16:94:45:0e:
+                    bd:d3:09:6b:d9:e0:03:fe:2a:00:10:9b:97:38:f0:
+                    53:11:5e:8d:7a:e6:a1:be:2e:32:a9:ff:63:4f:a0:
+                    c6:ea:35:b8:59:e4:ab:43:a2:48:c0:1a:08:11:be:
+                    6c:c3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Authority Key Identifier:
+                keyid:0F:80:61:1C:82:31:61:D5:2F:28:E7:8D:46:38:B4:2C:E1:C6:D9:E2
+
+            X509v3 Subject Key Identifier:
+                38:4D:B9:C6:AD:7D:6C:68:C2:5F:75:D7:1B:6E:CB:A6:E9:9E:3A:AD
+            X509v3 Subject Alternative Name:
+                DNS:revoked.badssl.com, DNS:www.revoked.badssl.com
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage:
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 CRL Distribution Points:
+
+                Full Name:
+                  URI:http://crl3.digicert.com/ssca-sha2-g6.crl
+
+                Full Name:
+                  URI:http://crl4.digicert.com/ssca-sha2-g6.crl
+
+            X509v3 Certificate Policies:
+                Policy: 2.16.840.1.114412.1.1
+                  CPS: https://www.digicert.com/CPS
+                Policy: 2.23.140.1.2.3
+
+            Authority Information Access:
+                OCSP - URI:http://ocsp.digicert.com
+                CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt
+
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            CT Precertificate SCTs:
+                Signed Certificate Timestamp:
+                    Version   : v1 (0x0)
+                    Log ID    : A4:B9:09:90:B4:18:58:14:87:BB:13:A2:CC:67:70:0A:
+                                3C:35:98:04:F9:1B:DF:B8:E3:77:CD:0E:C8:0D:DC:10
+                    Timestamp : Oct  4 22:42:58.127 2019 GMT
+                    Extensions: none
+                    Signature : ecdsa-with-SHA256
+                                30:44:02:20:58:F8:BC:EE:DE:4C:CC:99:EF:2C:32:46:
+                                98:2A:69:79:0C:32:1D:AD:55:92:F0:06:F3:5D:4C:83:
+                                5F:4A:6D:CB:02:20:3A:5B:B1:E8:E7:F0:57:A8:FE:90:
+                                F5:83:7C:54:1E:6F:72:D9:AE:4A:DD:94:F6:A8:E2:3E:
+                                15:FC:1A:35:C9:BB
+                Signed Certificate Timestamp:
+                    Version   : v1 (0x0)
+                    Log ID    : 87:75:BF:E7:59:7C:F8:8C:43:99:5F:BD:F3:6E:FF:56:
+                                8D:47:56:36:FF:4A:B5:60:C1:B4:EA:FF:5E:A0:83:0F
+                    Timestamp : Oct  4 22:42:58.234 2019 GMT
+                    Extensions: none
+                    Signature : ecdsa-with-SHA256
+                                30:45:02:21:00:99:C8:8D:4E:62:B7:C7:D1:79:D9:BF:
+                                A3:C9:0A:27:A2:38:F9:3D:1D:D4:4D:7E:C8:D4:46:36:
+                                CA:B6:F2:0D:5B:02:20:38:6B:50:2B:B0:82:98:CA:CD:
+                                D1:24:29:70:BC:A5:3A:CF:4F:BE:74:6B:0B:56:DB:C9:
+                                C2:4D:92:DA:09:56:F5
+                Signed Certificate Timestamp:
+                    Version   : v1 (0x0)
+                    Log ID    : 44:94:65:2E:B0:EE:CE:AF:C4:40:07:D8:A8:FE:28:C0:
+                                DA:E6:82:BE:D8:CB:31:B5:3F:D3:33:96:B5:B6:81:A8
+                    Timestamp : Oct  4 22:42:57.985 2019 GMT
+                    Extensions: none
+                    Signature : ecdsa-with-SHA256
+                                30:45:02:21:00:C1:79:D5:93:06:D6:2F:3B:A4:12:63:
+                                95:6E:CF:08:40:78:90:68:44:5C:0B:74:43:EC:8A:CA:
+                                1E:DE:1D:52:F3:02:20:57:D4:BF:A2:0B:D7:C1:3F:44:
+                                EB:AE:15:06:03:C1:9A:EF:0E:96:C2:8C:97:6F:17:0F:
+                                42:6F:EF:86:87:3C:C1
+    Signature Algorithm: sha256WithRSAEncryption
+         17:ce:77:03:d2:a3:25:b8:c1:59:0c:b3:b1:3f:37:af:e0:1e:
+         7a:6b:41:16:ed:7e:58:26:7c:b2:df:65:15:9a:cf:95:02:9e:
+         53:0c:33:75:90:0c:66:a6:17:9c:55:64:5c:e4:3a:44:9f:e6:
+         9c:5c:cd:e1:1f:3c:74:84:17:db:61:8a:40:00:dc:bd:e8:c4:
+         60:1a:0d:ea:60:83:75:e0:e5:7c:43:31:88:23:10:91:54:3c:
+         c7:dd:fe:e4:41:1d:5b:81:9b:c2:40:2e:9f:b3:72:67:44:9f:
+         25:3a:10:85:36:79:2d:ca:5a:f0:57:5a:78:f0:3c:71:05:42:
+         e3:23:5a:18:b5:72:a2:90:47:71:b3:b6:60:ba:53:88:a1:51:
+         42:48:fb:73:17:e3:1e:4b:0c:aa:62:ff:08:38:23:00:bd:b7:
+         2d:82:7b:2e:a3:47:9e:90:bc:95:94:93:93:7b:b0:b0:fa:18:
+         f3:e6:76:17:e7:20:9c:db:01:6e:d2:f9:4b:d2:4c:3c:77:a0:
+         da:4b:58:ac:64:16:79:a7:b7:c2:7d:56:5f:5b:85:8b:25:d8:
+         31:62:00:13:2a:84:e4:c5:51:69:71:33:ab:e1:3a:1d:18:4d:
+         c6:f1:f3:ae:e8:6f:c1:92:74:bd:af:78:39:a4:ba:56:68:d7:
+         3a:36:da:8a
+-----BEGIN CERTIFICATE-----
+MIIGvzCCBaegAwIBAgIQA3G1iob2zpw+y3v0L5II/DANBgkqhkiG9w0BAQsFADBN
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E
+aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTkxMDA0MDAwMDAwWhcN
+MjExMDA4MTIwMDAwWjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5p
+YTEVMBMGA1UEBxMMV2FsbnV0IENyZWVrMRwwGgYDVQQKExNMdWNhcyBHYXJyb24g
+VG9ycmVzMRswGQYDVQQDExJyZXZva2VkLmJhZHNzbC5jb20wggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC0Ljkn9nZW+vmCL6At8tAyGZlV3IlElvdzI6/3
+pF4+dL9Zec1fC+eP+wMZv4+eY9L/Anx2/hbpAvyGkF+YXNaaui6V6NilxfScnae5
+3rhKcWL9Kih9Aq9G1g0dcWHZTNuXFQA09FOBvI6UOd7YvkJ/JOoCU8ZbgD4RLtLZ
+C20Yhqwh1nfZSKlPo1sd86U2ZNZNH0a38zUQ9XtFOt2kGNu9o07DEJsZhOWWlZtd
+51ZyqyeFaRTc4V42zWnKc8CCB338fo0u+8vJeS6XNkMPFpRFDr3TCWvZ4AP+KgAQ
+m5c48FMRXo165qG+LjKp/2NPoMbqNbhZ5KtDokjAGggRvmzDAgMBAAGjggNyMIID
+bjAfBgNVHSMEGDAWgBQPgGEcgjFh1S8o541GOLQs4cbZ4jAdBgNVHQ4EFgQUOE25
+xq19bGjCX3XXG27LpumeOq0wNQYDVR0RBC4wLIIScmV2b2tlZC5iYWRzc2wuY29t
+ghZ3d3cucmV2b2tlZC5iYWRzc2wuY29tMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
+FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwawYDVR0fBGQwYjAvoC2gK4YpaHR0cDov
+L2NybDMuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwL6AtoCuGKWh0dHA6
+Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zc2NhLXNoYTItZzYuY3JsMEwGA1UdIARFMEMw
+NwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0
+LmNvbS9DUFMwCAYGZ4EMAQIDMHwGCCsGAQUFBwEBBHAwbjAkBggrBgEFBQcwAYYY
+aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEYGCCsGAQUFBzAChjpodHRwOi8vY2Fj
+ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyU2VjdXJlU2VydmVyQ0EuY3J0
+MAwGA1UdEwEB/wQCMAAwggF9BgorBgEEAdZ5AgQCBIIBbQSCAWkBZwB1AKS5CZC0
+GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABbZjwwc8AAAQDAEYwRAIgWPi8
+7t5MzJnvLDJGmCppeQwyHa1VkvAG811Mg19KbcsCIDpbsejn8Feo/pD1g3xUHm9y
+2a5K3ZT2qOI+FfwaNcm7AHYAh3W/51l8+IxDmV+9827/Vo1HVjb/SrVgwbTq/16g
+gw8AAAFtmPDCOgAABAMARzBFAiEAmciNTmK3x9F52b+jyQonojj5PR3UTX7I1EY2
+yrbyDVsCIDhrUCuwgpjKzdEkKXC8pTrPT750awtW28nCTZLaCVb1AHYARJRlLrDu
+zq/EQAfYqP4owNrmgr7YyzG1P9MzlrW2gagAAAFtmPDBQQAABAMARzBFAiEAwXnV
+kwbWLzukEmOVbs8IQHiQaERcC3RD7IrKHt4dUvMCIFfUv6IL18E/ROuuFQYDwZrv
+DpbCjJdvFw9Cb++GhzzBMA0GCSqGSIb3DQEBCwUAA4IBAQAXzncD0qMluMFZDLOx
+Pzev4B56a0EW7X5YJnyy32UVms+VAp5TDDN1kAxmphecVWRc5DpEn+acXM3hHzx0
+hBfbYYpAANy96MRgGg3qYIN14OV8QzGIIxCRVDzH3f7kQR1bgZvCQC6fs3JnRJ8l
+OhCFNnktylrwV1p48DxxBULjI1oYtXKikEdxs7ZgulOIoVFCSPtzF+MeSwyqYv8I
+OCMAvbctgnsuo0eekLyVlJOTe7Cw+hjz5nYX5yCc2wFu0vlL0kw8d6DaS1isZBZ5
+p7fCfVZfW4WLJdgxYgATKoTkxVFpcTOr4TodGE3G8fOu6G/BknS9r3g5pLpWaNc6
+NtqK
+-----END CERTIFICATE-----
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index 5f6121a5..5a1e5b7 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -3723,8 +3723,8 @@
       nullptr, &cache[0], cb.callback());
   ASSERT_THAT(cb.GetResult(rv), IsOk());
   rv = disk_cache::CreateCacheBackend(
-      net::MEDIA_CACHE, net::CACHE_BACKEND_DEFAULT, store2.GetPath(), 0, false,
-      nullptr, &cache[1], cb.callback());
+      net::GENERATED_BYTE_CODE_CACHE, net::CACHE_BACKEND_DEFAULT,
+      store2.GetPath(), 0, false, nullptr, &cache[1], cb.callback());
   ASSERT_THAT(cb.GetResult(rv), IsOk());
 
   ASSERT_TRUE(cache[0].get() != nullptr && cache[1].get() != nullptr);
diff --git a/net/disk_cache/blockfile/histogram_macros.h b/net/disk_cache/blockfile/histogram_macros.h
index 3a68177..a5de85cc 100644
--- a/net/disk_cache/blockfile/histogram_macros.h
+++ b/net/disk_cache/blockfile/histogram_macros.h
@@ -92,11 +92,11 @@
     const std::string my_name =                                      \
         CACHE_UMA_BACKEND_IMPL_OBJ->HistogramName(name, experiment); \
     switch (CACHE_UMA_BACKEND_IMPL_OBJ->GetCacheType()) {            \
+      case net::REMOVED_MEDIA_CACHE:                                 \
       default:                                                       \
         NOTREACHED();                                                \
         FALLTHROUGH;                                                 \
       case net::DISK_CACHE:                                          \
-      case net::MEDIA_CACHE:                                         \
       case net::APP_CACHE:                                           \
       case net::SHADER_CACHE:                                        \
       case net::PNACL_CACHE:                                         \
diff --git a/net/disk_cache/disk_cache.cc b/net/disk_cache/disk_cache.cc
index 169a8a9..b5d3315 100644
--- a/net/disk_cache/disk_cache.cc
+++ b/net/disk_cache/disk_cache.cc
@@ -243,7 +243,7 @@
       std::move(app_status_listener),
 #endif
       net_log, backend, std::move(post_cleanup_callback), std::move(callback));
-  if (type == net::DISK_CACHE || type == net::MEDIA_CACHE) {
+  if (type == net::DISK_CACHE) {
     DCHECK(!had_post_cleanup_callback);
     return creator->Run();
   }
diff --git a/net/disk_cache/disk_cache.h b/net/disk_cache/disk_cache.h
index 91aaa7d..c1d5f7a 100644
--- a/net/disk_cache/disk_cache.h
+++ b/net/disk_cache/disk_cache.h
@@ -52,9 +52,9 @@
 // Returns an instance of a Backend of the given |type|. |path| points to a
 // folder where the cached data will be stored (if appropriate). This cache
 // instance must be the only object that will be reading or writing files to
-// that folder (if another one exists, and |type| is not net::DISK_CACHE or
-// net::MEDIA_CACHE, this operation will not complete until the previous
-// duplicate gets destroyed and finishes all I/O).
+// that folder (if another one exists, and |type| is not net::DISK_CACHE this
+// operation will not complete until the previous duplicate gets destroyed and
+// finishes all I/O).
 //
 // The returned object should be deleted when not needed anymore.
 // If |force| is true, and there is a problem with the cache initialization, the
@@ -96,8 +96,7 @@
 // will get invoked even if the creation fails. The invocation will always be
 // via the event loop, and never direct.
 //
-// This is currently unsupported for |type| == net::DISK_CACHE or
-// net::MEDIA_CACHE.
+// This is currently unsupported for |type| == net::DISK_CACHE.
 //
 // Note that this will not wait for |post_cleanup_callback| of a previous
 // instance for |path| to run.
diff --git a/net/disk_cache/disk_cache_fuzzer.cc b/net/disk_cache/disk_cache_fuzzer.cc
index 2f1ee04..cc531029c 100644
--- a/net/disk_cache/disk_cache_fuzzer.cc
+++ b/net/disk_cache/disk_cache_fuzzer.cc
@@ -246,9 +246,10 @@
       MAYBE_PRINT << "Cache type = APP_CACHE." << std::endl;
       return net::CacheType::APP_CACHE;
       break;
-    case disk_cache_fuzzer::FuzzCommands::MEDIA_CACHE:
-      MAYBE_PRINT << "Cache type = MEDIA_CACHE." << std::endl;
-      return net::CacheType::MEDIA_CACHE;
+    case disk_cache_fuzzer::FuzzCommands::REMOVED_MEDIA_CACHE:
+      // Media cache no longer in use; handle as HTTP_CACHE
+      MAYBE_PRINT << "Cache type = REMOVED_MEDIA_CACHE." << std::endl;
+      return net::CacheType::DISK_CACHE;
       break;
     case disk_cache_fuzzer::FuzzCommands::SHADER_CACHE:
       MAYBE_PRINT << "Cache type = SHADER_CACHE." << std::endl;
diff --git a/net/disk_cache/disk_cache_fuzzer.proto b/net/disk_cache/disk_cache_fuzzer.proto
index 779bdb5..b9dbe08 100644
--- a/net/disk_cache/disk_cache_fuzzer.proto
+++ b/net/disk_cache/disk_cache_fuzzer.proto
@@ -25,7 +25,7 @@
 
   enum CacheType {
     APP_CACHE = 1;
-    MEDIA_CACHE = 2;
+    REMOVED_MEDIA_CACHE = 2;
     SHADER_CACHE = 3;
     PNACL_CACHE = 4;
     GENERATED_BYTE_CODE_CACHE = 5;
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index d92587d..3e609b9 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -2175,14 +2175,12 @@
 }
 
 TEST_F(DiskCacheEntryTest, UpdateSparseEntry) {
-  SetCacheType(net::MEDIA_CACHE);
   InitCache();
   UpdateSparseEntry();
 }
 
 TEST_F(DiskCacheEntryTest, MemoryOnlyUpdateSparseEntry) {
   SetMemoryOnlyMode();
-  SetCacheType(net::MEDIA_CACHE);
   InitCache();
   UpdateSparseEntry();
 }
diff --git a/net/disk_cache/simple/simple_histogram_macros.h b/net/disk_cache/simple/simple_histogram_macros.h
index e10764d..84d0a57 100644
--- a/net/disk_cache/simple/simple_histogram_macros.h
+++ b/net/disk_cache/simple/simple_histogram_macros.h
@@ -31,10 +31,6 @@
         SIMPLE_CACHE_THUNK(uma_type,                                        \
                            ("SimpleCache.App." uma_name, ##__VA_ARGS__));   \
         break;                                                              \
-      case net::MEDIA_CACHE:                                                \
-        SIMPLE_CACHE_THUNK(uma_type,                                        \
-                           ("SimpleCache.Media." uma_name, ##__VA_ARGS__)); \
-        break;                                                              \
       case net::GENERATED_BYTE_CODE_CACHE:                                  \
       case net::GENERATED_NATIVE_CODE_CACHE:                                \
       case net::SHADER_CACHE:                                               \
diff --git a/net/quic/quic_http3_logger.cc b/net/quic/quic_http3_logger.cc
index 698bd18..1b5f923f 100644
--- a/net/quic/quic_http3_logger.cc
+++ b/net/quic/quic_http3_logger.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "net/log/net_log_capture_mode.h"
 #include "net/log/net_log_event_type.h"
@@ -64,6 +65,24 @@
 
 void QuicHttp3Logger::OnSettingsFrameReceived(
     const quic::SettingsFrame& frame) {
+  // Increment value by one because empty SETTINGS frames are allowed,
+  // but histograms do not support the value zero.
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ReceivedSettings.CountPlusOne",
+                              frame.values.size() + 1, /* min = */ 1,
+                              /* max = */ 10, /* buckets = */ 10);
+  for (const auto& value : frame.values) {
+    if (value.first == quic::SETTINGS_QPACK_MAX_TABLE_CAPACITY) {
+      UMA_HISTOGRAM_COUNTS_10000(
+          "Net.QuicSession.ReceivedSettings.MaxTableCapacity", value.second);
+    } else if (value.first == quic::SETTINGS_MAX_HEADER_LIST_SIZE) {
+      UMA_HISTOGRAM_COUNTS_10000(
+          "Net.QuicSession.ReceivedSettings.MaxHeaderListSize", value.second);
+    } else if (value.first == quic::SETTINGS_QPACK_BLOCKED_STREAMS) {
+      UMA_HISTOGRAM_COUNTS_1000(
+          "Net.QuicSession.ReceivedSettings.BlockedStreams", value.second);
+    }
+  }
+
   if (!net_log_.IsCapturing())
     return;
   net_log_.AddEvent(NetLogEventType::HTTP3_SETTINGS_RECEIVED,
diff --git a/net/quic/quic_http3_logger.h b/net/quic/quic_http3_logger.h
index 9e583533..8a1b686 100644
--- a/net/quic/quic_http3_logger.h
+++ b/net/quic/quic_http3_logger.h
@@ -18,7 +18,7 @@
 namespace net {
 
 // This class is a debug visitor of a quic::QuicSpdySession which logs events
-// to |net_log|.
+// to |net_log| and records histograms.
 class NET_EXPORT_PRIVATE QuicHttp3Logger : public quic::Http3DebugVisitor {
  public:
   explicit QuicHttp3Logger(const NetLogWithSource& net_log);
diff --git a/net/reporting/reporting_delivery_agent.cc b/net/reporting/reporting_delivery_agent.cc
index 0c64f3c..73e0a91 100644
--- a/net/reporting/reporting_delivery_agent.cc
+++ b/net/reporting/reporting_delivery_agent.cc
@@ -229,8 +229,9 @@
       }
 
       // TODO: Calculate actual max depth.
+      // TODO(mmenke): Populate NetworkIsolationKey.
       uploader()->StartUpload(
-          report_origin, endpoint, json, max_depth,
+          report_origin, endpoint, NetworkIsolationKey(), json, max_depth,
           base::BindOnce(&ReportingDeliveryAgentImpl::OnUploadComplete,
                          weak_factory_.GetWeakPtr(), std::move(delivery)));
     }
diff --git a/net/reporting/reporting_test_util.cc b/net/reporting/reporting_test_util.cc
index 5b36fefb..d228e3a 100644
--- a/net/reporting/reporting_test_util.cc
+++ b/net/reporting/reporting_test_util.cc
@@ -16,6 +16,7 @@
 #include "base/test/simple_test_clock.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/timer/mock_timer.h"
+#include "net/base/network_isolation_key.h"
 #include "net/reporting/reporting_cache.h"
 #include "net/reporting/reporting_context.h"
 #include "net/reporting/reporting_delegate.h"
@@ -36,11 +37,13 @@
  public:
   PendingUploadImpl(const url::Origin& report_origin,
                     const GURL& url,
+                    const NetworkIsolationKey& network_isolation_key,
                     const std::string& json,
                     ReportingUploader::UploadCallback callback,
                     base::OnceCallback<void(PendingUpload*)> complete_callback)
       : report_origin_(report_origin),
         url_(url),
+        network_isolation_key_(network_isolation_key),
         json_(json),
         callback_(std::move(callback)),
         complete_callback_(std::move(complete_callback)) {}
@@ -64,6 +67,7 @@
  private:
   url::Origin report_origin_;
   GURL url_;
+  NetworkIsolationKey network_isolation_key_;
   std::string json_;
   ReportingUploader::UploadCallback callback_;
   base::OnceCallback<void(PendingUpload*)> complete_callback_;
@@ -98,13 +102,15 @@
 TestReportingUploader::TestReportingUploader() = default;
 TestReportingUploader::~TestReportingUploader() = default;
 
-void TestReportingUploader::StartUpload(const url::Origin& report_origin,
-                                        const GURL& url,
-                                        const std::string& json,
-                                        int max_depth,
-                                        UploadCallback callback) {
+void TestReportingUploader::StartUpload(
+    const url::Origin& report_origin,
+    const GURL& url,
+    const NetworkIsolationKey& network_isolation_key,
+    const std::string& json,
+    int max_depth,
+    UploadCallback callback) {
   pending_uploads_.push_back(std::make_unique<PendingUploadImpl>(
-      report_origin, url, json, std::move(callback),
+      report_origin, url, network_isolation_key, json, std::move(callback),
       base::BindOnce(&ErasePendingUpload, &pending_uploads_)));
 }
 
diff --git a/net/reporting/reporting_test_util.h b/net/reporting/reporting_test_util.h
index e75a721..68238d2b 100644
--- a/net/reporting/reporting_test_util.h
+++ b/net/reporting/reporting_test_util.h
@@ -37,6 +37,7 @@
 
 namespace net {
 
+class NetworkIsolationKey;
 struct ReportingEndpoint;
 class ReportingGarbageCollector;
 
@@ -81,6 +82,7 @@
 
   void StartUpload(const url::Origin& report_origin,
                    const GURL& url,
+                   const NetworkIsolationKey& network_isolation_key,
                    const std::string& json,
                    int max_depth,
                    UploadCallback callback) override;
diff --git a/net/reporting/reporting_uploader.cc b/net/reporting/reporting_uploader.cc
index 930a49f..d33e518 100644
--- a/net/reporting/reporting_uploader.cc
+++ b/net/reporting/reporting_uploader.cc
@@ -15,6 +15,7 @@
 #include "base/strings/string_util.h"
 #include "net/base/elements_upload_data_stream.h"
 #include "net/base/load_flags.h"
+#include "net/base/network_isolation_key.h"
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/http/http_response_headers.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -102,12 +103,14 @@
 
   PendingUpload(const url::Origin& report_origin,
                 const GURL& url,
+                const NetworkIsolationKey& network_isolation_key,
                 const std::string& json,
                 int max_depth,
                 ReportingUploader::UploadCallback callback)
       : state(CREATED),
         report_origin(report_origin),
         url(url),
+        network_isolation_key(network_isolation_key),
         payload_reader(UploadOwnedBytesElementReader::CreateWithString(json)),
         max_depth(max_depth),
         callback(std::move(callback)) {}
@@ -119,6 +122,7 @@
   State state;
   const url::Origin report_origin;
   const GURL url;
+  const NetworkIsolationKey network_isolation_key;
   std::unique_ptr<UploadElementReader> payload_reader;
   int max_depth;
   ReportingUploader::UploadCallback callback;
@@ -140,11 +144,13 @@
 
   void StartUpload(const url::Origin& report_origin,
                    const GURL& url,
+                   const NetworkIsolationKey& network_isolation_key,
                    const std::string& json,
                    int max_depth,
                    UploadCallback callback) override {
     auto upload = std::make_unique<PendingUpload>(
-        report_origin, url, json, max_depth, std::move(callback));
+        report_origin, url, network_isolation_key, json, max_depth,
+        std::move(callback));
     auto collector_origin = url::Origin::Create(url);
     if (collector_origin == report_origin) {
       // Skip the preflight check if the reports are being sent to the same
@@ -171,6 +177,7 @@
 
     upload->request->SetLoadFlags(LOAD_DISABLE_CACHE);
     upload->request->set_allow_credentials(false);
+    upload->request->set_network_isolation_key(upload->network_isolation_key);
 
     upload->request->SetExtraRequestHeaderByName(
         HttpRequestHeaders::kOrigin, upload->report_origin.Serialize(), true);
@@ -197,11 +204,11 @@
     upload->state = PendingUpload::SENDING_PAYLOAD;
     upload->request = context_->CreateRequest(upload->url, IDLE, this,
                                               kReportUploadTrafficAnnotation);
-
     upload->request->set_method("POST");
 
     upload->request->SetLoadFlags(LOAD_DISABLE_CACHE);
     upload->request->set_allow_credentials(false);
+    upload->request->set_network_isolation_key(upload->network_isolation_key);
 
     upload->request->SetExtraRequestHeaderByName(
         HttpRequestHeaders::kContentType, kUploadContentType, true);
diff --git a/net/reporting/reporting_uploader.h b/net/reporting/reporting_uploader.h
index 0f3948a..9fa0318 100644
--- a/net/reporting/reporting_uploader.h
+++ b/net/reporting/reporting_uploader.h
@@ -19,6 +19,7 @@
 
 namespace net {
 
+class NetworkIsolationKey;
 class URLRequestContext;
 
 // Uploads already-serialized reports and converts responses to one of the
@@ -37,6 +38,7 @@
   // |report_origin| must be that origin.
   virtual void StartUpload(const url::Origin& report_origin,
                            const GURL& url,
+                           const NetworkIsolationKey& network_isolation_key,
                            const std::string& json,
                            int max_depth,
                            UploadCallback callback) = 0;
diff --git a/net/reporting/reporting_uploader_unittest.cc b/net/reporting/reporting_uploader_unittest.cc
index 7618c118..f3e0edf 100644
--- a/net/reporting/reporting_uploader_unittest.cc
+++ b/net/reporting/reporting_uploader_unittest.cc
@@ -11,9 +11,13 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "net/base/features.h"
+#include "net/base/network_isolation_key.h"
 #include "net/cookies/cookie_store.h"
 #include "net/cookies/cookie_store_test_callbacks.h"
 #include "net/http/http_status_code.h"
+#include "net/socket/socket_test_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
@@ -132,8 +136,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 }
 
@@ -143,8 +147,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback.outcome());
@@ -156,7 +160,8 @@
   ASSERT_TRUE(server_.ShutdownAndWaitUntilComplete());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, url, kUploadBody, 0, callback.callback());
+  uploader_->StartUpload(kOrigin, url, NetworkIsolationKey(), kUploadBody, 0,
+                         callback.callback());
   callback.WaitForCall();
 
   EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
@@ -168,8 +173,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
@@ -182,8 +187,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
@@ -207,8 +212,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_TRUE(preflight_received);
@@ -224,7 +229,8 @@
 
   TestUploadCallback callback;
   auto server_origin = url::Origin::Create(server_.base_url());
-  uploader_->StartUpload(server_origin, server_.GetURL("/"), kUploadBody, 0,
+  uploader_->StartUpload(server_origin, server_.GetURL("/"),
+                         NetworkIsolationKey(), kUploadBody, 0,
                          callback.callback());
   callback.WaitForCall();
 
@@ -250,8 +256,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
@@ -280,8 +286,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
@@ -310,8 +316,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
@@ -340,8 +346,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_EQ(ReportingUploader::Outcome::FAILURE, callback.outcome());
@@ -354,8 +360,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_EQ(ReportingUploader::Outcome::REMOVE_ENDPOINT, callback.outcome());
@@ -398,8 +404,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_TRUE(followed);
@@ -421,8 +427,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, callback.callback());
   callback.WaitForCall();
 
   EXPECT_FALSE(followed);
@@ -452,8 +458,8 @@
   ASSERT_TRUE(cookie_callback.result().IsInclude());
 
   TestUploadCallback upload_callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         upload_callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, upload_callback.callback());
   upload_callback.WaitForCall();
 }
 
@@ -473,8 +479,8 @@
   ASSERT_TRUE(server_.Start());
 
   TestUploadCallback upload_callback;
-  uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                         upload_callback.callback());
+  uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                         kUploadBody, 0, upload_callback.callback());
   upload_callback.WaitForCall();
 
   GetCookieListCallback cookie_callback;
@@ -512,20 +518,139 @@
 
   {
     TestUploadCallback callback;
-    uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                           callback.callback());
+    uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                           kUploadBody, 0, callback.callback());
     callback.WaitForCall();
   }
   EXPECT_EQ(1, request_count);
 
   {
     TestUploadCallback callback;
-    uploader_->StartUpload(kOrigin, server_.GetURL("/"), kUploadBody, 0,
-                           callback.callback());
+    uploader_->StartUpload(kOrigin, server_.GetURL("/"), NetworkIsolationKey(),
+                           kUploadBody, 0, callback.callback());
     callback.WaitForCall();
   }
   EXPECT_EQ(2, request_count);
 }
 
+// Create two requests with the same NetworkIsolationKey, and one request with a
+// different one, and make sure only the requests with the same
+// NetworkIsolationKey share a socket.
+TEST_F(ReportingUploaderTest, RespectsNetworkIsolationKey) {
+  // While features::kPartitionConnectionsByNetworkIsolationKey is not needed
+  // for reporting code to respect NetworkIsolationKeys, this test works by
+  // ensuring that Reporting's NetworkIsolationKey makes it to the socket pool
+  // layer and is respected there, so this test needs to enable
+  // kPartitionConnectionsByNetworkIsolationKey.
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
+
+  const url::Origin kOrigin2 = url::Origin::Create(GURL("https://origin2/"));
+  ASSERT_NE(kOrigin, kOrigin2);
+  const NetworkIsolationKey kNetworkIsolationKey1(kOrigin, kOrigin);
+  const NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2);
+
+  MockClientSocketFactory socket_factory;
+  TestURLRequestContext context(true /* delay_initialization */);
+  context.set_client_socket_factory(&socket_factory);
+  context.Init();
+
+  // First socket handles first and third requests.
+  MockWrite writes1[] = {
+      MockWrite(SYNCHRONOUS, 0,
+                "POST /1 HTTP/1.1\r\n"
+                "Host: origin\r\n"
+                "Connection: keep-alive\r\n"
+                "Content-Length: 2\r\n"
+                "Content-Type: application/reports+json\r\n"
+                "User-Agent: \r\n"
+                "Accept-Encoding: gzip, deflate\r\n"
+                "Accept-Language: en-us,fr\r\n\r\n"),
+      MockWrite(SYNCHRONOUS, 1, kUploadBody),
+      MockWrite(SYNCHRONOUS, 3,
+                "POST /3 HTTP/1.1\r\n"
+                "Host: origin\r\n"
+                "Connection: keep-alive\r\n"
+                "Content-Length: 2\r\n"
+                "Content-Type: application/reports+json\r\n"
+                "User-Agent: \r\n"
+                "Accept-Encoding: gzip, deflate\r\n"
+                "Accept-Language: en-us,fr\r\n\r\n"),
+      MockWrite(SYNCHRONOUS, 4, kUploadBody),
+  };
+  MockRead reads1[] = {
+      MockRead(SYNCHRONOUS, 2,
+               "HTTP/1.1 200 OK\r\n"
+               "Connection: Keep-Alive\r\n"
+               "Content-Length: 0\r\n\r\n"),
+      MockRead(SYNCHRONOUS, 5,
+               "HTTP/1.1 200 OK\r\n"
+               "Connection: Keep-Alive\r\n"
+               "Content-Length: 0\r\n\r\n"),
+  };
+  SequencedSocketData data1(reads1, writes1);
+  socket_factory.AddSocketDataProvider(&data1);
+  SSLSocketDataProvider ssl_data1(ASYNC, OK);
+  socket_factory.AddSSLSocketDataProvider(&ssl_data1);
+
+  // Second socket handles second request.
+  MockWrite writes2[] = {
+      MockWrite(SYNCHRONOUS, 0,
+                "POST /2 HTTP/1.1\r\n"
+                "Host: origin\r\n"
+                "Connection: keep-alive\r\n"
+                "Content-Length: 2\r\n"
+                "Content-Type: application/reports+json\r\n"
+                "User-Agent: \r\n"
+                "Accept-Encoding: gzip, deflate\r\n"
+                "Accept-Language: en-us,fr\r\n\r\n"),
+      MockWrite(SYNCHRONOUS, 1, kUploadBody),
+  };
+  MockRead reads2[] = {
+      MockRead(SYNCHRONOUS, 2,
+               "HTTP/1.1 200 OK\r\n"
+               "Connection: Keep-Alive\r\n"
+               "Content-Length: 0\r\n\r\n"),
+  };
+  SequencedSocketData data2(reads2, writes2);
+  socket_factory.AddSocketDataProvider(&data2);
+  SSLSocketDataProvider ssl_data2(ASYNC, OK);
+  socket_factory.AddSSLSocketDataProvider(&ssl_data2);
+
+  TestUploadCallback callback1;
+  std::unique_ptr<ReportingUploader> uploader1 =
+      ReportingUploader::Create(&context);
+  uploader1->StartUpload(kOrigin, GURL("https://origin/1"),
+                         kNetworkIsolationKey1, kUploadBody, 0,
+                         callback1.callback());
+  callback1.WaitForCall();
+  EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback1.outcome());
+
+  // Start two more requests in parallel. The first started uses a different
+  // NetworkIsolationKey, so should create a new socket, while the second one
+  // gets the other socket. Start in parallel to make sure that a new socket
+  // isn't created just because the first is returned to the socket pool
+  // asynchronously.
+  TestUploadCallback callback2;
+  std::unique_ptr<ReportingUploader> uploader2 =
+      ReportingUploader::Create(&context);
+  uploader2->StartUpload(kOrigin, GURL("https://origin/2"),
+                         kNetworkIsolationKey2, kUploadBody, 0,
+                         callback2.callback());
+  TestUploadCallback callback3;
+  std::unique_ptr<ReportingUploader> uploader3 =
+      ReportingUploader::Create(&context);
+  uploader3->StartUpload(kOrigin, GURL("https://origin/3"),
+                         kNetworkIsolationKey1, kUploadBody, 0,
+                         callback3.callback());
+
+  callback2.WaitForCall();
+  EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback2.outcome());
+
+  callback3.WaitForCall();
+  EXPECT_EQ(ReportingUploader::Outcome::SUCCESS, callback3.outcome());
+}
+
 }  // namespace
 }  // namespace net
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index bd4b73c..9260e5e 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -5566,6 +5566,16 @@
     return TestGroupId("a", 443, ClientSocketPool::SocketType::kSsl);
   }
 
+  static ClientSocketPool::GroupId GetGroupIdInPartition() {
+    // Note this GroupId will match GetGroupId() unless
+    // kPartitionConnectionsByNetworkIsolationKey is enabled.
+    const auto kOrigin = url::Origin::Create(GURL("https://b/"));
+    const NetworkIsolationKey kNetworkIsolationKey(kOrigin, kOrigin);
+    return TestGroupId("a", 443, ClientSocketPool::SocketType::kSsl,
+                       PrivacyMode::PRIVACY_MODE_DISABLED,
+                       kNetworkIsolationKey);
+  }
+
   void OnSSLConfigForServerChanged() {
     switch (GetParam()) {
       case RefreshType::kServer:
@@ -5614,18 +5624,28 @@
 }
 
 TEST_P(ClientSocketPoolBaseRefreshTest, RefreshGroupClosesIdleConnectJobs) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
+
   CreatePoolForRefresh(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
   const ClientSocketPool::GroupId kGroupId = GetGroupId();
+  const ClientSocketPool::GroupId kGroupIdInPartition = GetGroupIdInPartition();
 
   pool_->RequestSockets(kGroupId, params_, base::nullopt, 2,
                         NetLogWithSource());
+  pool_->RequestSockets(kGroupIdInPartition, params_, base::nullopt, 2,
+                        NetLogWithSource());
   ASSERT_TRUE(pool_->HasGroupForTesting(kGroupId));
-  EXPECT_EQ(2, pool_->IdleSocketCount());
+  ASSERT_TRUE(pool_->HasGroupForTesting(kGroupIdInPartition));
+  EXPECT_EQ(4, pool_->IdleSocketCount());
   EXPECT_EQ(2u, pool_->IdleSocketCountInGroup(kGroupId));
+  EXPECT_EQ(2u, pool_->IdleSocketCountInGroup(kGroupIdInPartition));
 
   OnSSLConfigForServerChanged();
   EXPECT_EQ(0, pool_->IdleSocketCount());
   EXPECT_FALSE(pool_->HasGroupForTesting(kGroupId));
+  EXPECT_FALSE(pool_->HasGroupForTesting(kGroupIdInPartition));
 }
 
 TEST_F(ClientSocketPoolBaseTest,
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index e61df67..df4f720 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -745,12 +745,6 @@
   RetryAllOperations();
 }
 
-static bool EnforceTLS13DowngradeForKnownRootsOnly() {
-  return base::FeatureList::IsEnabled(features::kEnforceTLS13Downgrade) &&
-         base::GetFieldTrialParamByFeatureAsBool(
-             features::kEnforceTLS13Downgrade, "known_roots_only", true);
-}
-
 int SSLClientSocketImpl::Init() {
   DCHECK(!ssl_);
 
@@ -814,8 +808,7 @@
 
   SSL_set_early_data_enabled(ssl_.get(), ssl_config_.early_data_enabled);
 
-  if (!base::FeatureList::IsEnabled(features::kEnforceTLS13Downgrade) ||
-      EnforceTLS13DowngradeForKnownRootsOnly()) {
+  if (!context_->config().tls13_hardening_for_local_anchors_enabled) {
     SSL_set_ignore_tls13_downgrade(ssl_.get(), 1);
   }
 
@@ -1010,8 +1003,7 @@
     }
   }
 
-  if (!base::FeatureList::IsEnabled(features::kEnforceTLS13Downgrade) ||
-      EnforceTLS13DowngradeForKnownRootsOnly()) {
+  if (!context_->config().tls13_hardening_for_local_anchors_enabled) {
     // Record metrics on the TLS 1.3 anti-downgrade mechanism. This is only
     // recorded when enforcement is disabled. (When enforcement is enabled,
     // the connection will fail with ERR_TLS13_DOWNGRADE_DETECTED.) See
@@ -1061,8 +1053,7 @@
                                   type);
       }
 
-      if (EnforceTLS13DowngradeForKnownRootsOnly() &&
-          server_cert_verify_result_.is_issued_by_known_root) {
+      if (server_cert_verify_result_.is_issued_by_known_root) {
         // Exit DoHandshakeLoop and return the result to the caller to
         // Connect.
         DCHECK_EQ(STATE_NONE, next_handshake_state_);
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 490d8d4..57914bc 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -5356,273 +5356,55 @@
 #endif  // OS_ANDROID
 }
 
-// Test downgrade enforcement works for the 1.3 to 1.2 downgrade.
-TEST_F(SSLClientSocketTest, TLS13DowngradeEnforcedAtTLS12) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeatureWithParameters(
-      features::kEnforceTLS13Downgrade, {{"known_roots_only", "false"}});
+// Test downgrade enforcement behaves as expected.
+TEST_F(SSLClientSocketTest, TLS13DowngradeEnforced) {
+  for (auto tls_max_version :
+       {SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_0,
+        SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_1,
+        SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_2}) {
+    for (bool downgrade : {false, true}) {
+      SCOPED_TRACE(downgrade);
+      SCOPED_TRACE(tls_max_version);
+      SpawnedTestServer::SSLOptions ssl_options;
+      ssl_options.simulate_tls13_downgrade = downgrade;
+      ssl_options.tls_max_version = tls_max_version;
+      ASSERT_TRUE(StartTestServer(ssl_options));
+      scoped_refptr<X509Certificate> server_cert =
+          spawned_test_server()->GetCertificate();
 
-  SpawnedTestServer::SSLOptions ssl_options;
-  ssl_options.simulate_tls13_downgrade = true;
-  ssl_options.tls_max_version =
-      SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_2;
-  ASSERT_TRUE(StartTestServer(ssl_options));
+      for (bool enable_for_local_anchors : {false, true}) {
+        SCOPED_TRACE(enable_for_local_anchors);
+        SSLContextConfig config;
+        config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
+        config.tls13_hardening_for_local_anchors_enabled =
+            enable_for_local_anchors;
+        ssl_config_service_->UpdateSSLConfigAndNotify(config);
 
-  SSLContextConfig config;
-  config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-  ssl_config_service_->UpdateSSLConfigAndNotify(config);
+        for (bool known_root : {false, true}) {
+          SCOPED_TRACE(known_root);
+          CertVerifyResult verify_result;
+          verify_result.is_issued_by_known_root = known_root;
+          verify_result.verified_cert = server_cert;
+          cert_verifier_->ClearRules();
+          cert_verifier_->AddResultForCert(server_cert.get(), verify_result,
+                                           OK);
 
-  int rv;
-  ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-  EXPECT_THAT(rv, IsError(ERR_TLS13_DOWNGRADE_DETECTED));
-  EXPECT_FALSE(sock_->IsConnected());
-}
+          bool should_enforce = known_root || enable_for_local_anchors;
 
-// Test downgrade enforcement works for the 1.3 to 1.1 downgrade.
-TEST_F(SSLClientSocketTest, TLS13DowngradeEnforcedAtTLS11) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeatureWithParameters(
-      features::kEnforceTLS13Downgrade, {{"known_roots_only", "false"}});
-
-  SpawnedTestServer::SSLOptions ssl_options;
-  ssl_options.simulate_tls12_downgrade = true;
-  ssl_options.tls_max_version =
-      SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_1;
-  ASSERT_TRUE(StartTestServer(ssl_options));
-
-  SSLContextConfig config;
-  config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-  ssl_config_service_->UpdateSSLConfigAndNotify(config);
-
-  int rv;
-  ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-  EXPECT_THAT(rv, IsError(ERR_TLS13_DOWNGRADE_DETECTED));
-  EXPECT_FALSE(sock_->IsConnected());
-}
-
-// Test downgrade enforcement works for the 1.3 to 1.0 downgrade.
-TEST_F(SSLClientSocketTest, TLS13DowngradeEnforcedAtTLS10) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeatureWithParameters(
-      features::kEnforceTLS13Downgrade, {{"known_roots_only", "false"}});
-
-  SpawnedTestServer::SSLOptions ssl_options;
-  ssl_options.simulate_tls12_downgrade = true;
-  ssl_options.tls_max_version =
-      SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_0;
-  ASSERT_TRUE(StartTestServer(ssl_options));
-
-  SSLContextConfig config;
-  config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-  ssl_config_service_->UpdateSSLConfigAndNotify(config);
-
-  int rv;
-  ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-  EXPECT_THAT(rv, IsError(ERR_TLS13_DOWNGRADE_DETECTED));
-  EXPECT_FALSE(sock_->IsConnected());
-}
-
-// Test downgrade enforcement lets valid connections through.
-TEST_F(SSLClientSocketTest, TLS13DowngradeValid) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kEnforceTLS13Downgrade);
-
-  SpawnedTestServer::SSLOptions ssl_options;
-  ssl_options.tls_max_version =
-      SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_2;
-  ASSERT_TRUE(StartTestServer(ssl_options));
-
-  SSLContextConfig config;
-  config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-  ssl_config_service_->UpdateSSLConfigAndNotify(config);
-
-  int rv;
-  ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-  EXPECT_THAT(rv, IsOk());
-  EXPECT_TRUE(sock_->IsConnected());
-
-  SSLInfo info;
-  EXPECT_TRUE(sock_->GetSSLInfo(&info));
-  EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_2,
-            SSLConnectionStatusToVersion(info.connection_status));
-}
-
-// Test the downgrade is not enforced for the TLS 1.3 to TLS 1.2 downgrade if
-// disabled.
-TEST_F(SSLClientSocketTest, TLS13DowngradeIgnoredAtTLS12) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(features::kEnforceTLS13Downgrade);
-
-  SpawnedTestServer::SSLOptions ssl_options;
-  ssl_options.tls_max_version =
-      SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_2;
-  ssl_options.simulate_tls13_downgrade = true;
-  ASSERT_TRUE(StartTestServer(ssl_options));
-
-  SSLContextConfig config;
-  config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-  ssl_config_service_->UpdateSSLConfigAndNotify(config);
-
-  int rv;
-  ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-  EXPECT_THAT(rv, IsOk());
-  EXPECT_TRUE(sock_->IsConnected());
-
-  SSLInfo info;
-  EXPECT_TRUE(sock_->GetSSLInfo(&info));
-  EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_2,
-            SSLConnectionStatusToVersion(info.connection_status));
-}
-
-// Test the downgrade is not enforced for the TLS 1.3 to TLS 1.1 downgrade if
-// disabled.
-TEST_F(SSLClientSocketTest, TLS13DowngradeIgnoredAtTLS11) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(features::kEnforceTLS13Downgrade);
-
-  SpawnedTestServer::SSLOptions ssl_options;
-  ssl_options.simulate_tls12_downgrade = true;
-  ssl_options.tls_max_version =
-      SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_1;
-  ASSERT_TRUE(StartTestServer(ssl_options));
-
-  SSLContextConfig config;
-  config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-  ssl_config_service_->UpdateSSLConfigAndNotify(config);
-
-  int rv;
-  ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-  EXPECT_THAT(rv, IsOk());
-  EXPECT_TRUE(sock_->IsConnected());
-
-  SSLInfo info;
-  EXPECT_TRUE(sock_->GetSSLInfo(&info));
-  EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_1,
-            SSLConnectionStatusToVersion(info.connection_status));
-}
-
-// Test the downgrade is not enforced for the TLS 1.3 to TLS 1.0 downgrade if
-// disabled.
-TEST_F(SSLClientSocketTest, TLS13DowngradeIgnoredAtTLS10) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(features::kEnforceTLS13Downgrade);
-
-  SpawnedTestServer::SSLOptions ssl_options;
-  ssl_options.simulate_tls13_downgrade = true;
-  ssl_options.tls_max_version =
-      SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_0;
-  ASSERT_TRUE(StartTestServer(ssl_options));
-
-  SSLContextConfig config;
-  config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-  ssl_config_service_->UpdateSSLConfigAndNotify(config);
-
-  int rv;
-  ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-  EXPECT_THAT(rv, IsOk());
-  EXPECT_TRUE(sock_->IsConnected());
-
-  SSLInfo info;
-  EXPECT_TRUE(sock_->GetSSLInfo(&info));
-  EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1,
-            SSLConnectionStatusToVersion(info.connection_status));
-}
-
-// Failed on Android builder. See https://crbug.com/999647
-#if defined(OS_ANDROID)
-#define MAYBE_TLS13DowngradeEnforcedKnownKnown \
-  DISABLED_TLS13DowngradeEnforcedKnownKnown
-#else
-#define MAYBE_TLS13DowngradeEnforcedKnownKnown TLS13DowngradeEnforcedKnownKnown
-#endif
-// Test downgrade enforcement enforces known roots when configured to.
-TEST_F(SSLClientSocketTest, MAYBE_TLS13DowngradeEnforcedKnownKnown) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeatureWithParameters(
-      features::kEnforceTLS13Downgrade, {{"known_roots_only", "true"}});
-
-  SpawnedTestServer::SSLOptions ssl_options;
-  ssl_options.simulate_tls13_downgrade = true;
-  ssl_options.tls_max_version =
-      SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_2;
-  ASSERT_TRUE(StartTestServer(ssl_options));
-
-  scoped_refptr<X509Certificate> server_cert =
-      spawned_test_server()->GetCertificate();
-
-  // Certificate is trusted and chains to a public root.
-  CertVerifyResult verify_result;
-  verify_result.is_issued_by_known_root = true;
-  verify_result.verified_cert = server_cert;
-  cert_verifier_->AddResultForCert(server_cert.get(), verify_result, OK);
-
-  SSLContextConfig config;
-  config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-  ssl_config_service_->UpdateSSLConfigAndNotify(config);
-
-  int rv;
-  ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-  EXPECT_THAT(rv, IsError(ERR_TLS13_DOWNGRADE_DETECTED));
-  EXPECT_FALSE(sock_->IsConnected());
-}
-
-// Test downgrade enforcement allows valid connections with known roots when
-// configured to.
-TEST_F(SSLClientSocketTest, TLS13DowngradeEnforcedKnownValid) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeatureWithParameters(
-      features::kEnforceTLS13Downgrade, {{"known_roots_only", "true"}});
-
-  ASSERT_TRUE(StartTestServer(SpawnedTestServer::SSLOptions()));
-
-  scoped_refptr<X509Certificate> server_cert =
-      spawned_test_server()->GetCertificate();
-
-  // Certificate is trusted and chains to a public root.
-  CertVerifyResult verify_result;
-  verify_result.is_issued_by_known_root = true;
-  verify_result.verified_cert = server_cert;
-  cert_verifier_->AddResultForCert(server_cert.get(), verify_result, OK);
-
-  SSLContextConfig config;
-  config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-  ssl_config_service_->UpdateSSLConfigAndNotify(config);
-
-  int rv;
-  ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-  EXPECT_THAT(rv, IsOk());
-  EXPECT_TRUE(sock_->IsConnected());
-}
-
-// Test downgrade enforcement ignores unknown roots when configured to.
-TEST_F(SSLClientSocketTest, TLS13DowngradeEnforcedKnownUnknown) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeatureWithParameters(
-      features::kEnforceTLS13Downgrade, {{"known_roots_only", "true"}});
-
-  SpawnedTestServer::SSLOptions ssl_options;
-  ssl_options.simulate_tls13_downgrade = true;
-  ssl_options.tls_max_version =
-      SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_2;
-  ASSERT_TRUE(StartTestServer(ssl_options));
-
-  scoped_refptr<X509Certificate> server_cert =
-      spawned_test_server()->GetCertificate();
-
-  // Certificate is trusted and chains to a public root.
-  CertVerifyResult verify_result;
-  verify_result.is_issued_by_known_root = false;
-  verify_result.verified_cert = server_cert;
-  cert_verifier_->AddResultForCert(server_cert.get(), verify_result, OK);
-
-  SSLContextConfig config;
-  config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-  ssl_config_service_->UpdateSSLConfigAndNotify(config);
-
-  int rv;
-  ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
-  EXPECT_THAT(rv, IsOk());
-  EXPECT_TRUE(sock_->IsConnected());
+          ssl_client_session_cache_->Flush();
+          int rv;
+          ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
+          if (should_enforce && downgrade) {
+            EXPECT_THAT(rv, IsError(ERR_TLS13_DOWNGRADE_DETECTED));
+            EXPECT_FALSE(sock_->IsConnected());
+          } else {
+            EXPECT_THAT(rv, IsOk());
+            EXPECT_TRUE(sock_->IsConnected());
+          }
+        }
+      }
+    }
+  }
 }
 
 struct TLS13DowngradeMetricsParams {
@@ -5691,10 +5473,6 @@
   const TLS13DowngradeMetricsParams& params = GetParam();
   base::HistogramTester histograms;
 
-  // Metrics are only gathered when enforcement is disabled.
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(features::kEnforceTLS13Downgrade);
-
   SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.simulate_tls13_downgrade = params.downgrade;
   ssl_options.key_exchanges = params.key_exchanges;
@@ -5729,7 +5507,7 @@
   std::unique_ptr<SSLClientSocket> ssl_socket =
       CreateSSLClientSocket(std::move(transport), host_port_pair, SSLConfig());
   rv = callback.GetResult(ssl_socket->Connect(callback.callback()));
-  EXPECT_THAT(rv, IsOk());
+  EXPECT_THAT(rv, AnyOf(IsOk(), IsError(ERR_TLS13_DOWNGRADE_DETECTED)));
 
   histograms.ExpectUniqueSample("Net.SSLTLS13Downgrade", params.downgrade, 1);
   if (params.tls13_experiment_host) {
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc
index de40f29..d1823b2 100644
--- a/net/socket/transport_client_socket_pool.cc
+++ b/net/socket/transport_client_socket_pool.cc
@@ -800,7 +800,6 @@
 
 void TransportClientSocketPool::OnSSLConfigForServerChanged(
     const HostPortPair& server) {
-  bool refreshed_any = false;
   // Current time value. Retrieving it once at the function start rather than
   // inside the inner loop, since it shouldn't change by any meaningful amount.
   //
@@ -809,28 +808,20 @@
   // interfaces so the parameter is not necessary.
   base::TimeTicks now = base::TimeTicks::Now();
 
-  if (proxy_server_.is_http_like() && !proxy_server_.is_http() &&
-      proxy_server_.host_port_pair() == server) {
-    // If the proxy is |server| and uses SSL settings (HTTPS or QUIC), refresh
-    // every group.
-    refreshed_any = !group_map_.empty();
-    for (auto it = group_map_.begin(); it != group_map_.end();) {
-      auto to_refresh = it++;
+  // If the proxy is |server| and uses SSL settings (HTTPS or QUIC), refresh
+  // every group.
+  bool proxy_matches = proxy_server_.is_http_like() &&
+                       !proxy_server_.is_http() &&
+                       proxy_server_.host_port_pair() == server;
+  bool refreshed_any = false;
+  for (auto it = group_map_.begin(); it != group_map_.end();) {
+    auto to_refresh = it++;
+    if (proxy_matches || (to_refresh->first.socket_type() == SocketType::kSsl &&
+                          to_refresh->first.destination() == server)) {
+      refreshed_any = true;
       // Note this call may destroy the group and invalidate |to_refresh|.
       RefreshGroup(to_refresh, now);
     }
-  } else {
-    // Refresh the credentialed and uncredentialed pools for |server|.
-    for (auto privacy_mode : {PrivacyMode::PRIVACY_MODE_DISABLED,
-                              PrivacyMode::PRIVACY_MODE_ENABLED}) {
-      auto it =
-          group_map_.find(GroupId(server, SocketType::kSsl, privacy_mode));
-      if (it != group_map_.end()) {
-        refreshed_any = true;
-        // Note this call may destroy the group and invalidate |it|.
-        RefreshGroup(it, now);
-      }
-    }
   }
 
   if (refreshed_any) {
diff --git a/net/ssl/ssl_config_service.cc b/net/ssl/ssl_config_service.cc
index a35d6b0a..354b660 100644
--- a/net/ssl/ssl_config_service.cc
+++ b/net/ssl/ssl_config_service.cc
@@ -17,9 +17,11 @@
 bool SSLContextConfigsAreEqual(const net::SSLContextConfig& config1,
                                const net::SSLContextConfig& config2) {
   return std::tie(config1.version_min, config1.version_max,
-                  config1.disabled_cipher_suites) ==
+                  config1.disabled_cipher_suites,
+                  config1.tls13_hardening_for_local_anchors_enabled) ==
          std::tie(config2.version_min, config2.version_max,
-                  config2.disabled_cipher_suites);
+                  config2.disabled_cipher_suites,
+                  config2.tls13_hardening_for_local_anchors_enabled);
 }
 
 }  // namespace
diff --git a/net/ssl/ssl_config_service.h b/net/ssl/ssl_config_service.h
index 73c7080b..c1d2269c 100644
--- a/net/ssl/ssl_config_service.h
+++ b/net/ssl/ssl_config_service.h
@@ -38,6 +38,10 @@
   // Ex: To disable TLS_RSA_WITH_RC4_128_MD5, specify 0x0004, while to
   // disable TLS_ECDH_ECDSA_WITH_RC4_128_SHA, specify 0xC002.
   std::vector<uint16_t> disabled_cipher_suites;
+
+  // If true, enables TLS 1.3 downgrade hardening for connections using
+  // local trust anchors. (Hardening for known roots is always enabled.)
+  bool tls13_hardening_for_local_anchors_enabled = false;
 };
 
 // The interface for retrieving global SSL configuration.  This interface
diff --git a/net/ssl/ssl_config_service_unittest.cc b/net/ssl/ssl_config_service_unittest.cc
index 15d06cc..3828a72f 100644
--- a/net/ssl/ssl_config_service_unittest.cc
+++ b/net/ssl/ssl_config_service_unittest.cc
@@ -122,6 +122,11 @@
   EXPECT_CALL(observer, OnSSLContextConfigChanged()).Times(1);
   mock_service.SetSSLContextConfig(initial_config);
 
+  // Ensure that toggling TLS 1.3 hardening triggers an update.
+  initial_config.tls13_hardening_for_local_anchors_enabled = true;
+  EXPECT_CALL(observer, OnSSLContextConfigChanged()).Times(1);
+  mock_service.SetSSLContextConfig(initial_config);
+
   mock_service.RemoveObserver(&observer);
 }
 
diff --git a/net/url_request/url_request_context_builder_unittest.cc b/net/url_request/url_request_context_builder_unittest.cc
index eee1294..35571c3 100644
--- a/net/url_request/url_request_context_builder_unittest.cc
+++ b/net/url_request/url_request_context_builder_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/run_loop.h"
 #include "build/build_config.h"
+#include "net/base/network_isolation_key.h"
 #include "net/base/request_priority.h"
 #include "net/base/test_completion_callback.h"
 #include "net/dns/host_resolver.h"
@@ -196,7 +197,8 @@
   // Queue a pending upload.
   GURL url("https://www.foo.test");
   context->reporting_service()->GetContextForTesting()->uploader()->StartUpload(
-      url::Origin::Create(url), url, "report body", 0, base::DoNothing());
+      url::Origin::Create(url), url, NetworkIsolationKey(), "report body", 0,
+      base::DoNothing());
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(1, context->reporting_service()
                    ->GetContextForTesting()
diff --git a/remoting/android/java/res/layout/notification_dialog.xml b/remoting/android/java/res/layout/notification_dialog.xml
new file mode 100644
index 0000000..fddb3e8
--- /dev/null
+++ b/remoting/android/java/res/layout/notification_dialog.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:orientation="vertical"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:paddingStart="20dp"
+        android:paddingEnd="20dp">
+    <CheckBox android:id="@+id/silence_checkbox"
+            android:text="@string/dont_show_again"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"/>
+</LinearLayout>
diff --git a/remoting/android/java/src/org/chromium/chromoting/jni/NotificationPresenter.java b/remoting/android/java/src/org/chromium/chromoting/jni/NotificationPresenter.java
index 716de68..c253cd0 100644
--- a/remoting/android/java/src/org/chromium/chromoting/jni/NotificationPresenter.java
+++ b/remoting/android/java/src/org/chromium/chromoting/jni/NotificationPresenter.java
@@ -5,10 +5,14 @@
 package org.chromium.chromoting.jni;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.net.Uri;
 import android.support.v7.app.AlertDialog;
+import android.view.View;
+import android.widget.CheckBox;
 
 import androidx.annotation.IntDef;
 
@@ -20,6 +24,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /** Helper for fetching and presenting a notification */
 @JNINamespace("remoting")
@@ -32,6 +37,19 @@
         int FETCHED = 2;
     }
 
+    @IntDef({NotificationUiState.NOT_SHOWN, NotificationUiState.SHOWN,
+            NotificationUiState.SILENCED})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface NotificationUiState {
+        int NOT_SHOWN = 0;
+        int SHOWN = 1;
+        int SILENCED = 2;
+    }
+
+    private static final String PREFERENCE_UI_STATE = "notification_ui_state";
+    private static final String PREFERENCE_LAST_SEEN_MESSAGE_ID =
+            "notification_last_seen_message_id";
+
     private final long mNativeJniNotificationPresenter;
     private final Activity mActivity;
 
@@ -65,11 +83,28 @@
     }
 
     @CalledByNative
-    void onNotificationFetched(String messageText, String linkText, String linkUrl) {
+    void onNotificationFetched(String messageId, String messageText, String linkText,
+            String linkUrl, boolean allowSilence) {
         Preconditions.isTrue(mState == State.FETCHING);
         mState = State.FETCHED;
 
-        // TODO(yuweih): Add Don't Show Again support.
+        SharedPreferences preferences = mActivity.getPreferences(Context.MODE_PRIVATE);
+        @NotificationUiState
+        int uiState = preferences.getInt(PREFERENCE_UI_STATE, NotificationUiState.NOT_SHOWN);
+        String lastSeenMessageId = preferences.getString(PREFERENCE_LAST_SEEN_MESSAGE_ID, "");
+
+        if (allowSilence && uiState == NotificationUiState.SILENCED
+                && Objects.equals(lastSeenMessageId, messageId)) {
+            return;
+        }
+
+        if (!Objects.equals(lastSeenMessageId, messageId)) {
+            preferences.edit()
+                    .putInt(PREFERENCE_UI_STATE, NotificationUiState.NOT_SHOWN)
+                    .putString(PREFERENCE_LAST_SEEN_MESSAGE_ID, messageId)
+                    .apply();
+        }
+
         final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
         builder.setMessage(messageText);
         builder.setPositiveButton(linkText, (DialogInterface dialog, int id) -> {
@@ -81,6 +116,23 @@
                         -> {
                                 // Do nothing
                         });
+        CheckBox silenceCheckBox;
+        if (allowSilence && uiState == NotificationUiState.SHOWN) {
+            View notificationDialog =
+                    mActivity.getLayoutInflater().inflate(R.layout.notification_dialog, null);
+            builder.setView(notificationDialog);
+            silenceCheckBox = notificationDialog.findViewById(R.id.silence_checkbox);
+        } else {
+            silenceCheckBox = null;
+        }
+        builder.setOnDismissListener((DialogInterface dialog) -> {
+            @NotificationUiState
+            int newState = (silenceCheckBox != null && silenceCheckBox.isChecked())
+                    ? NotificationUiState.SILENCED
+                    : NotificationUiState.SHOWN;
+            preferences.edit().putInt(PREFERENCE_UI_STATE, newState).apply();
+        });
+
         final AlertDialog dialog = builder.create();
         dialog.show();
     }
diff --git a/remoting/base/service_urls.cc b/remoting/base/service_urls.cc
index 8c786af..a8ede62 100644
--- a/remoting/base/service_urls.cc
+++ b/remoting/base/service_urls.cc
@@ -7,10 +7,8 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "google_apis/google_api_keys.h"
-#include "remoting/base/remoting_bot.h"
 
 // Configurable service data.
-constexpr char kDirectoryBaseUrl[] = "https://www.googleapis.com/chromoting/v1";
 constexpr char kGcdBaseUrl[] = "https://www.googleapis.com/clouddevices/v1";
 constexpr char kGcdJid[] = "clouddevices.gserviceaccount.com";
 constexpr char kFtlServerEndpoint[] = "instantmessaging-pa.googleapis.com";
@@ -18,24 +16,16 @@
 
 // Command line switches.
 #if !defined(NDEBUG)
-constexpr char kDirectoryBaseUrlSwitch[] = "directory-base-url";
 constexpr char kGcdBaseUrlSwitch[] = "gcd-base-url";
-constexpr char kDirectoryBotJidSwitch[] = "directory-bot-jid";
 constexpr char kGcdJidSwitch[] = "gcd-jid";
 constexpr char kFtlServerEndpointSwitch[] = "ftl-server-endpoint";
 constexpr char kRemotingServerEndpointSwitch[] = "remoting-server-endpoint";
 #endif  // !defined(NDEBUG)
 
-// Non-configurable service paths.
-constexpr char kDirectoryHostsSuffix[] = "/@me/hosts/";
-constexpr char kDirectoryIceConfigSuffix[] = "/@me/iceconfig";
-
 namespace remoting {
 
 ServiceUrls::ServiceUrls()
-    : directory_base_url_(kDirectoryBaseUrl),
-      gcd_base_url_(kGcdBaseUrl),
-      directory_bot_jid_(kRemotingBotJid),
+    : gcd_base_url_(kGcdBaseUrl),
       gcd_jid_(kGcdJid),
       ftl_server_endpoint_(kFtlServerEndpoint),
       remoting_server_endpoint_(kRemotingServerEndpoint) {
@@ -45,17 +35,9 @@
     // Allow debug builds to override urls via command line.
     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
     CHECK(command_line);
-    if (command_line->HasSwitch(kDirectoryBaseUrlSwitch)) {
-      directory_base_url_ =
-          command_line->GetSwitchValueASCII(kDirectoryBaseUrlSwitch);
-    }
     if (command_line->HasSwitch(kGcdBaseUrlSwitch)) {
       gcd_base_url_ = command_line->GetSwitchValueASCII(kGcdBaseUrlSwitch);
     }
-    if (command_line->HasSwitch(kDirectoryBotJidSwitch)) {
-      directory_bot_jid_ =
-          command_line->GetSwitchValueASCII(kDirectoryBotJidSwitch);
-    }
     if (command_line->HasSwitch(kGcdJidSwitch)) {
       gcd_jid_ = command_line->GetSwitchValueASCII(kGcdJidSwitch);
     }
@@ -69,9 +51,6 @@
     }
   }
 #endif  // !defined(NDEBUG)
-
-  directory_hosts_url_ = directory_base_url_ + kDirectoryHostsSuffix;
-  ice_config_url_ = directory_base_url_ + kDirectoryIceConfigSuffix;
 }
 
 ServiceUrls::~ServiceUrls() = default;
diff --git a/remoting/base/service_urls.h b/remoting/base/service_urls.h
index 2a69048..1624d2b3 100644
--- a/remoting/base/service_urls.h
+++ b/remoting/base/service_urls.h
@@ -21,21 +21,11 @@
   static ServiceUrls* GetInstance();
 
   // Remoting directory REST API URLs.
-  const std::string& directory_base_url() const { return directory_base_url_; }
-  const std::string& directory_hosts_url() const {
-    return directory_hosts_url_;
-  }
   const std::string& gcd_base_url() const { return gcd_base_url_; }
 
-  // Remoting directory bot JID (for registering hosts, logging, heartbeats).
-  const std::string& directory_bot_jid() const { return directory_bot_jid_; }
-
   // JID for communicating with GCD.
   const std::string& gcd_jid() const { return gcd_jid_; }
 
-  // ICE config URL.
-  const std::string& ice_config_url() const { return ice_config_url_; }
-
   const std::string& ftl_server_endpoint() const {
     return ftl_server_endpoint_;
   }
@@ -44,13 +34,6 @@
     return remoting_server_endpoint_;
   }
 
-#if !defined(NDEBUG)
-  // Override the directory bot JID for testing.
-  void set_directory_bot_jid(const std::string& bot_jid) {
-    directory_bot_jid_ = bot_jid;
-  }
-#endif
-
  private:
   friend struct base::DefaultSingletonTraits<ServiceUrls>;
 
@@ -60,7 +43,6 @@
   std::string directory_base_url_;
   std::string directory_hosts_url_;
   std::string gcd_base_url_;
-  std::string directory_bot_jid_;
   std::string gcd_jid_;
   std::string ice_config_url_;
   std::string ftl_server_endpoint_;
diff --git a/remoting/client/jni/jni_notification_presenter.cc b/remoting/client/jni/jni_notification_presenter.cc
index 9339af6f..03706b0 100644
--- a/remoting/client/jni/jni_notification_presenter.cc
+++ b/remoting/client/jni/jni_notification_presenter.cc
@@ -57,12 +57,15 @@
     Java_NotificationPresenter_onNoNotification(env, java_presenter);
     return;
   }
+  auto j_message_id = ConvertUTF8ToJavaString(env, notification->message_id);
   auto j_message_text =
       ConvertUTF8ToJavaString(env, notification->message_text);
   auto j_link_text = ConvertUTF8ToJavaString(env, notification->link_text);
   auto j_link_url = ConvertUTF8ToJavaString(env, notification->link_url);
+  auto j_allow_silence = notification->allow_silence;
   Java_NotificationPresenter_onNotificationFetched(
-      env, java_presenter, j_message_text, j_link_text, j_link_url);
+      env, java_presenter, j_message_id, j_message_text, j_link_text,
+      j_link_url, j_allow_silence);
 }
 
 static jlong JNI_NotificationPresenter_Init(
diff --git a/remoting/client/notification/notification_client.cc b/remoting/client/notification/notification_client.cc
index 20bb15f..6c613f2 100644
--- a/remoting/client/notification/notification_client.cc
+++ b/remoting/client/notification/notification_client.cc
@@ -304,8 +304,8 @@
   auto message = base::make_optional<NotificationMessage>();
   message->message_id = message_id;
   message->link_url = link_url;
-  message->allow_dont_show_again = false;
-  FindKeyAndGet(rule, "allow_dont_show_again", &message->allow_dont_show_again);
+  message->allow_silence = false;
+  FindKeyAndGet(rule, "allow_silence", &message->allow_silence);
   *out_message_text_filename = message_text_filename;
   *out_link_text_filename = link_text_filename;
   return message;
diff --git a/remoting/client/notification/notification_client_unittest.cc b/remoting/client/notification/notification_client_unittest.cc
index 0baf47a..76bfd6f7 100644
--- a/remoting/client/notification/notification_client_unittest.cc
+++ b/remoting/client/notification/notification_client_unittest.cc
@@ -65,7 +65,7 @@
   rule.SetStringKey("link_text", "link_text.json");
   rule.SetStringKey("link_url", "https://example.com/some_link");
   rule.SetIntKey("percent", 100);
-  rule.SetBoolKey("allow_dont_show_again", true);
+  rule.SetBoolKey("allow_silence", true);
   return rule;
 }
 
@@ -82,7 +82,7 @@
   message.message_text = "zh-CN:message";
   message.link_text = "zh-CN:link";
   message.link_url = "https://example.com/some_link";
-  message.allow_dont_show_again = true;
+  message.allow_silence = true;
   return message;
 }
 
@@ -311,10 +311,10 @@
   client_->GetNotification(kTestEmail, callback.Get());
 }
 
-TEST_F(NotificationClientTest, AllowDontShowAgainNotSet_DefaultToFalse) {
+TEST_F(NotificationClientTest, AllowSilenceNotSet_DefaultToFalse) {
   base::Value rules(base::Value::Type::LIST);
   base::Value rule = CreateDefaultRule();
-  rule.RemoveKey("allow_dont_show_again");
+  rule.RemoveKey("allow_silence");
   rules.Append(std::move(rule));
   EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
       .WillOnce(ReturnByMove(std::move(rules)));
@@ -324,7 +324,7 @@
       .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
 
   NotificationMessage notification = CreateDefaultNotification();
-  notification.allow_dont_show_again = false;
+  notification.allow_silence = false;
   base::MockCallback<NotificationClient::NotificationCallback> callback;
   EXPECT_CALL(callback, Run(MessageMatches(notification)));
   client_->GetNotification(kTestEmail, callback.Get());
diff --git a/remoting/client/notification/notification_message.h b/remoting/client/notification/notification_message.h
index b1486d0a..2a59169 100644
--- a/remoting/client/notification/notification_message.h
+++ b/remoting/client/notification/notification_message.h
@@ -22,7 +22,7 @@
   std::string message_text;
   std::string link_text;
   std::string link_url;
-  bool allow_dont_show_again;
+  bool allow_silence;
 };
 
 }  // namespace remoting
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index db432ae..d0fd9fd 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -573,7 +573,6 @@
   std::string local_jid;
   std::string host_jid;
   std::string host_public_key;
-  std::string directory_bot_jid;
   if (!data.GetString("hostJid", &host_jid) ||
       !data.GetString("hostPublicKey", &host_public_key) ||
       !data.GetString("localJid", &local_jid) ||
@@ -585,12 +584,6 @@
   data.GetString("clientPairingId", &client_auth_config.pairing_client_id);
   data.GetString("clientPairedSecret", &client_auth_config.pairing_secret);
 
-#if !defined(NDEBUG)
-  if (data.GetString("directoryBotJid", &directory_bot_jid)) {
-    ServiceUrls::GetInstance()->set_directory_bot_jid(directory_bot_jid);
-  }
-#endif
-
   if (use_async_pin_dialog_) {
     client_auth_config.fetch_secret_callback = base::Bind(
         &ChromotingInstance::FetchSecretFromDialog, weak_factory_.GetWeakPtr());
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc
index 7357cc1..b721380 100644
--- a/remoting/host/it2me/it2me_host.cc
+++ b/remoting/host/it2me/it2me_host.cc
@@ -91,7 +91,6 @@
     base::WeakPtr<It2MeHost::Observer> observer,
     std::unique_ptr<SignalStrategy> signal_strategy,
     const std::string& username,
-    const std::string& directory_bot_jid,
     const protocol::IceConfig& ice_config) {
   DCHECK(host_context->ui_task_runner()->BelongsToCurrentThread());
 
@@ -110,9 +109,9 @@
 
   // Switch to the network thread to start the actual connection.
   host_context_->network_task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&It2MeHost::ConnectOnNetworkThread, this,
-                                username, directory_bot_jid, ice_config,
-                                std::move(register_request)));
+      FROM_HERE,
+      base::BindOnce(&It2MeHost::ConnectOnNetworkThread, this, username,
+                     ice_config, std::move(register_request)));
 }
 
 void It2MeHost::Disconnect() {
@@ -123,7 +122,6 @@
 
 void It2MeHost::ConnectOnNetworkThread(
     const std::string& username,
-    const std::string& directory_bot_jid,
     const protocol::IceConfig& ice_config,
     std::unique_ptr<RegisterSupportHostRequest> register_request) {
   DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
diff --git a/remoting/host/it2me/it2me_host.h b/remoting/host/it2me/it2me_host.h
index 713e705..7f7b800 100644
--- a/remoting/host/it2me/it2me_host.h
+++ b/remoting/host/it2me/it2me_host.h
@@ -94,7 +94,6 @@
       base::WeakPtr<It2MeHost::Observer> observer,
       std::unique_ptr<SignalStrategy> signal_strategy,
       const std::string& username,
-      const std::string& directory_bot_jid,
       const protocol::IceConfig& ice_config);
 
   // Disconnects and shuts down the host.
@@ -144,7 +143,6 @@
   // Task posted to the network thread from Connect().
   void ConnectOnNetworkThread(
       const std::string& username,
-      const std::string& directory_bot_jid,
       const protocol::IceConfig& ice_config,
       std::unique_ptr<RegisterSupportHostRequest> register_request);
 
diff --git a/remoting/host/it2me/it2me_host_unittest.cc b/remoting/host/it2me/it2me_host_unittest.cc
index 8465645..7ed3fa61 100644
--- a/remoting/host/it2me/it2me_host_unittest.cc
+++ b/remoting/host/it2me/it2me_host_unittest.cc
@@ -298,12 +298,11 @@
   auto log_to_server = std::make_unique<XmppLogToServer>(
       ServerLogEntry::IT2ME, fake_signal_strategy.get(), "fake_bot_jid",
       host_context_->network_task_runner());
-  it2me_host_->Connect(host_context_->Copy(), policies_->CreateDeepCopy(),
-                       std::move(dialog_factory),
-                       std::move(register_host_request),
-                       std::move(log_to_server), weak_factory_.GetWeakPtr(),
-                       std::move(fake_signal_strategy), kTestUserName,
-                       "fake_bot_jid", ice_config);
+  it2me_host_->Connect(
+      host_context_->Copy(), policies_->CreateDeepCopy(),
+      std::move(dialog_factory), std::move(register_host_request),
+      std::move(log_to_server), weak_factory_.GetWeakPtr(),
+      std::move(fake_signal_strategy), kTestUserName, ice_config);
 
   base::RunLoop run_loop;
   state_change_callback_ =
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index a6b2e81..f16e81e 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -27,7 +27,6 @@
 #include "remoting/base/auto_thread_task_runner.h"
 #include "remoting/base/name_value_map.h"
 #include "remoting/base/passthrough_oauth_token_getter.h"
-#include "remoting/base/service_urls.h"
 #include "remoting/host/chromoting_host_context.h"
 #include "remoting/host/host_exit_codes.h"
 #include "remoting/host/it2me/it2me_confirmation_dialog.h"
@@ -74,6 +73,7 @@
 #endif  // defined(OS_WIN)
 
 constexpr char kAnonymousUserName[] = "anonymous_user";
+const char kRemotingBotJid[] = "remoting@bot.talk.google.com";
 
 // Helper functions to run |callback| asynchronously on the correct thread
 // using |task_runner|.
@@ -248,9 +248,6 @@
   bool terminate_upon_input = false;
   message->GetBoolean("terminateUponInput", &terminate_upon_input);
 
-  std::string directory_bot_jid =
-      ServiceUrls::GetInstance()->directory_bot_jid();
-
   std::unique_ptr<SignalStrategy> signal_strategy;
   std::unique_ptr<RegisterSupportHostRequest> register_host_request;
   std::unique_ptr<LogToServer> log_to_server;
@@ -261,9 +258,9 @@
     }
     signal_strategy = CreateDelegatedSignalStrategy(message.get());
     register_host_request =
-        std::make_unique<XmppRegisterSupportHostRequest>(directory_bot_jid);
+        std::make_unique<XmppRegisterSupportHostRequest>(kRemotingBotJid);
     log_to_server = std::make_unique<XmppLogToServer>(
-        ServerLogEntry::IT2ME, signal_strategy.get(), directory_bot_jid,
+        ServerLogEntry::IT2ME, signal_strategy.get(), kRemotingBotJid,
         host_context_->network_task_runner());
   } else {
     std::string access_token = ExtractAccessToken(message.get());
@@ -281,14 +278,6 @@
     return;
   }
 
-#if !defined(NDEBUG)
-  if (!message->GetString("directoryBotJid", &directory_bot_jid)) {
-    LOG(ERROR) << "'directoryBotJid' not found in request.";
-    SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
-    return;
-  }
-#endif  // !defined(NDEBUG)
-
   base::DictionaryValue* ice_config_dict;
   protocol::IceConfig ice_config;
   if (message->GetDictionary("iceConfig", &ice_config_dict)) {
@@ -313,11 +302,11 @@
   it2me_host_->set_enable_dialogs(!no_dialogs);
   it2me_host_->set_terminate_upon_input(terminate_upon_input);
 #endif
-  it2me_host_->Connect(
-      host_context_->Copy(), std::move(policies),
-      std::make_unique<It2MeConfirmationDialogFactory>(),
-      std::move(register_host_request), std::move(log_to_server), weak_ptr_,
-      std::move(signal_strategy), username, directory_bot_jid, ice_config);
+  it2me_host_->Connect(host_context_->Copy(), std::move(policies),
+                       std::make_unique<It2MeConfirmationDialogFactory>(),
+                       std::move(register_host_request),
+                       std::move(log_to_server), weak_ptr_,
+                       std::move(signal_strategy), username, ice_config);
 
   SendMessageToClient(std::move(response));
 }
diff --git a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
index 283cbc97..6985bad 100644
--- a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
@@ -48,7 +48,6 @@
 constexpr base::TimeDelta kTestAccessCodeLifetime =
     base::TimeDelta::FromSeconds(666);
 const char kTestClientUsername[] = "some_user@gmail.com";
-const char kTestBotJid[] = "remoting@bot.talk.google.com";
 const char kTestStunServer[] = "test_relay_server.com";
 
 void VerifyId(std::unique_ptr<base::DictionaryValue> response,
@@ -91,7 +90,6 @@
   connect_message.SetString("type", "connect");
   connect_message.SetString("xmppServerAddress", "talk.google.com:5222");
   connect_message.SetBoolean("xmppServerUseTls", true);
-  connect_message.SetString("directoryBotJid", kTestBotJid);
   connect_message.SetString("userName", kTestClientUsername);
   connect_message.SetString("authServiceWithToken", "oauth2:sometoken");
   connect_message.Set("iceConfig",
@@ -124,7 +122,6 @@
                base::WeakPtr<It2MeHost::Observer> observer,
                std::unique_ptr<SignalStrategy> signal_strategy,
                const std::string& username,
-               const std::string& directory_bot_jid,
                const protocol::IceConfig& ice_config) override;
   void Disconnect() override;
 
@@ -145,13 +142,11 @@
     base::WeakPtr<It2MeHost::Observer> observer,
     std::unique_ptr<SignalStrategy> signal_strategy,
     const std::string& username,
-    const std::string& directory_bot_jid,
     const protocol::IceConfig& ice_config) {
   DCHECK(context->ui_task_runner()->BelongsToCurrentThread());
 
   // Verify that parameters are passed correctly.
   EXPECT_EQ(username, kTestClientUsername);
-  EXPECT_EQ(directory_bot_jid, kTestBotJid);
   EXPECT_EQ(ice_config.stun_servers[0].hostname(), kTestStunServer);
 
   host_context_ = std::move(context);
diff --git a/remoting/ios/app/notification_dialog_view_controller.h b/remoting/ios/app/notification_dialog_view_controller.h
index 200abe0..10cf1ee 100644
--- a/remoting/ios/app/notification_dialog_view_controller.h
+++ b/remoting/ios/app/notification_dialog_view_controller.h
@@ -11,14 +11,14 @@
 struct NotificationMessage;
 }  // namespace remoting
 
-using NotificationDialogCompletionBlock = void (^)(BOOL isDontShowAgainOn);
+using NotificationDialogCompletionBlock = void (^)(BOOL silenced);
 
 // This is the view controller for showing the notification dialog.
 @interface NotificationDialogViewController : UIViewController
 
 - (instancetype)initWithNotificationMessage:
                     (const remoting::NotificationMessage&)message
-              shouldShowDontShowAgainToggle:(BOOL)shouldShowDontShowAgainToggle;
+                               allowSilence:(BOOL)allowSilence;
 
 - (void)presentOnTopVCWithCompletion:
     (NotificationDialogCompletionBlock)completion;
diff --git a/remoting/ios/app/notification_dialog_view_controller.mm b/remoting/ios/app/notification_dialog_view_controller.mm
index 1a8a894..c76a504 100644
--- a/remoting/ios/app/notification_dialog_view_controller.mm
+++ b/remoting/ios/app/notification_dialog_view_controller.mm
@@ -32,29 +32,29 @@
   NSString* _messageText;
   NSString* _linkText;
   NSURL* _linkUrl;
-  BOOL _shouldShowDontShowAgainToggle;
+  BOOL _allowSilence;
   NotificationDialogCompletionBlock _completion;
   MDCDialogTransitionController* _transitionController;
   UILabel* _messageLabel;
   MDCButton* _linkButton;
   MDCButton* _dismissButton;
 
-  // These will be nil if |_shouldShowDontShowAgainToggle| is NO.
+  // These will be nil if |_allowSilence| is NO.
   UISwitch* _dontShowAgainSwitch;
   UILabel* _dontShowAgainLabel;
 }
 
 #pragma mark - UIViewController
 
-- (instancetype)
-      initWithNotificationMessage:(const remoting::NotificationMessage&)message
-    shouldShowDontShowAgainToggle:(BOOL)shouldShowDontShowAgainToggle {
+- (instancetype)initWithNotificationMessage:
+                    (const remoting::NotificationMessage&)message
+                               allowSilence:(BOOL)allowSilence {
   self = [super init];
   if (self) {
     _messageText = base::SysUTF8ToNSString(message.message_text);
     _linkText = base::SysUTF8ToNSString(message.link_text);
     _linkUrl = [NSURL URLWithString:base::SysUTF8ToNSString(message.link_url)];
-    _shouldShowDontShowAgainToggle = shouldShowDontShowAgainToggle;
+    _allowSilence = allowSilence;
 
     _transitionController = [MDCDialogTransitionController new];
     self.modalPresentationStyle = UIModalPresentationCustom;
@@ -130,7 +130,7 @@
     [_linkButton.heightAnchor constraintEqualToConstant:kButtonHeight],
   ]];
 
-  if (_shouldShowDontShowAgainToggle) {
+  if (_allowSilence) {
     // This is to allow user to toggle switch by tapping the label. Tap events
     // won't be bubbled down to the switch.
     UITapGestureRecognizer* dontShowAgainTapGestureRecognizer =
@@ -187,7 +187,7 @@
               _linkButton.intrinsicContentSize.width);
   CGFloat contentHeight = _messageLabel.intrinsicContentSize.height +
                           2 * kLabelInset + kButtonHeight;
-  if (_shouldShowDontShowAgainToggle) {
+  if (_allowSilence) {
     contentWidth =
         MAX(contentWidth,
             kSwitchInset + _dontShowAgainSwitch.intrinsicContentSize.width +
diff --git a/remoting/ios/app/notification_presenter.mm b/remoting/ios/app/notification_presenter.mm
index f122d1d6..97808a30d 100644
--- a/remoting/ios/app/notification_presenter.mm
+++ b/remoting/ios/app/notification_presenter.mm
@@ -36,8 +36,8 @@
 
 enum NotificationUiState : unsigned int {
   NOT_SHOWN = 0,
-  SHOWN_AT_LEAST_ONCE = 1,
-  USER_CHOSE_DONT_SHOW_AGAIN = 2,
+  SHOWN = 1,
+  SILENCED = 2,
 };
 
 NotificationUiState NSNumberToUiState(NSNumber* number) {
@@ -124,8 +124,7 @@
           objectForFlag:RemotingFlagLastSeenNotificationMessageId]);
   NotificationUiState ui_state = NSNumberToUiState([RemotingPreferences.instance
       objectForFlag:RemotingFlagNotificationUiState]);
-  if (notification->allow_dont_show_again &&
-      ui_state == USER_CHOSE_DONT_SHOW_AGAIN &&
+  if (notification->allow_silence && ui_state == SILENCED &&
       last_seen_message_id == notification->message_id) {
     return;
   }
@@ -140,15 +139,13 @@
     [RemotingPreferences.instance synchronizeFlags];
   }
 
-  BOOL shouldShowDontShowAgain =
-      notification->allow_dont_show_again && ui_state == SHOWN_AT_LEAST_ONCE;
+  BOOL allowSilence = notification->allow_silence && ui_state == SHOWN;
   NotificationDialogViewController* dialogVc =
       [[NotificationDialogViewController alloc]
-            initWithNotificationMessage:*notification
-          shouldShowDontShowAgainToggle:shouldShowDontShowAgain];
-  [dialogVc presentOnTopVCWithCompletion:^(BOOL isDontShowAgainOn) {
-    NotificationUiState new_ui_state =
-        isDontShowAgainOn ? USER_CHOSE_DONT_SHOW_AGAIN : SHOWN_AT_LEAST_ONCE;
+          initWithNotificationMessage:*notification
+                         allowSilence:allowSilence];
+  [dialogVc presentOnTopVCWithCompletion:^(BOOL isSilenced) {
+    NotificationUiState new_ui_state = isSilenced ? SILENCED : SHOWN;
     [RemotingPreferences.instance setObject:UiStateToNSNumber(new_ui_state)
                                     forFlag:RemotingFlagNotificationUiState];
     [RemotingPreferences.instance synchronizeFlags];
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd
index 52f55b1..02114d0 100644
--- a/remoting/resources/remoting_strings.grd
+++ b/remoting/resources/remoting_strings.grd
@@ -662,7 +662,7 @@
         <message name="IDS_DISMISS" desc="Label for button to dismiss a dialog" formatter_data="android_java">
           Dismiss
         </message>
-        <message name="IDS_DONT_SHOW_AGAIN" desc="Label for checkbox to make a dialog not showing again.">
+        <message name="IDS_DONT_SHOW_AGAIN" desc="Label for checkbox to make a dialog not showing again." formatter_data="android_java">
           Don't show again
         </message>
       </if>  <!-- is_android or is_ios -->
diff --git a/remoting/signaling/signaling_address.cc b/remoting/signaling/signaling_address.cc
index 1165610..c2435b3 100644
--- a/remoting/signaling/signaling_address.cc
+++ b/remoting/signaling/signaling_address.cc
@@ -11,7 +11,6 @@
 #include "base/strings/stringprintf.h"
 #include "remoting/base/name_value_map.h"
 #include "remoting/base/remoting_bot.h"
-#include "remoting/base/service_urls.h"
 #include "remoting/signaling/jid_util.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 
@@ -84,7 +83,7 @@
       break;
     case SignalingAddress::Channel::LCS:
       endpoint_id_ = NormalizeJid(address);
-      jid_ = remoting::ServiceUrls::GetInstance()->directory_bot_jid();
+      jid_ = kRemotingBotJid;
       break;
     case SignalingAddress::Channel::FTL:
       jid_ = NormalizeJid(address);
diff --git a/remoting/test/it2me_cli_host.cc b/remoting/test/it2me_cli_host.cc
index bc728d5..6bc85b9 100644
--- a/remoting/test/it2me_cli_host.cc
+++ b/remoting/test/it2me_cli_host.cc
@@ -41,12 +41,8 @@
 // Connect message parameters:
 constexpr char kCRDConnectUserName[] = "userName";
 constexpr char kCRDConnectAuth[] = "authServiceWithToken";
-constexpr char kCRDConnectDirectoryBot[] = "directoryBotJid";
 constexpr char kCRDConnectNoDialogs[] = "noDialogs";
 
-// Connect message parameter values:
-constexpr char kCRDConnectDirectoryBotValue[] = "remoting@bot.talk.google.com";
-
 // CRD host states we care about:
 constexpr char kCRDStateKey[] = "state";
 constexpr char kCRDStateError[] = "ERROR";
@@ -216,8 +212,6 @@
 
   connect_params.SetKey(kCRDConnectUserName, base::Value(user_email));
   connect_params.SetKey(kCRDConnectAuth, base::Value("oauth2:" + access_token));
-  connect_params.SetKey(kCRDConnectDirectoryBot,
-                        base::Value(kCRDConnectDirectoryBotValue));
   connect_params.SetKey(kCRDConnectNoDialogs, base::Value(true));
   connect_params_ = std::move(connect_params);
 
diff --git a/services/device/geolocation/position_cache_impl_perftest.cc b/services/device/geolocation/position_cache_impl_perftest.cc
index 0d8a5f8..7dd90b8 100644
--- a/services/device/geolocation/position_cache_impl_perftest.cc
+++ b/services/device/geolocation/position_cache_impl_perftest.cc
@@ -13,7 +13,23 @@
 #include "base/time/time.h"
 #include "services/device/geolocation/position_cache_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
+#include "testing/perf/perf_result_reporter.h"
+
+namespace {
+
+constexpr char kMetricPrefixPositionCacheImpl[] = "PositionCacheImpl.";
+constexpr char kMetricAddTimeMs[] = "add_time";
+constexpr char kMetricFindTimeMs[] = "find_time";
+constexpr char kStoryBaseline[] = "baseline_story";
+
+perf_test::PerfResultReporter SetUpReporter(const std::string& story) {
+  perf_test::PerfResultReporter reporter(kMetricPrefixPositionCacheImpl, story);
+  reporter.RegisterImportantMetric(kMetricAddTimeMs, "ms");
+  reporter.RegisterImportantMetric(kMetricFindTimeMs, "ms");
+  return reporter;
+}
+
+}  // namespace
 
 namespace device {
 
@@ -42,9 +58,8 @@
   for (const auto& pair : data_)
     cache_.CachePosition(pair.first, pair.second);
   base::Time end = base::Time::Now();
-  perf_test::PrintResult("adding_to_cache", "", "",
-                         base::TimeDelta(end - start).InMillisecondsF(),
-                         "ms per batch", true);
+  auto reporter = SetUpReporter(kStoryBaseline);
+  reporter.AddResult(kMetricAddTimeMs, base::TimeDelta(end - start));
 }
 
 TEST_F(PositionCacheImplPerfTest, Finding) {
@@ -54,8 +69,7 @@
   for (const auto& pair : data_)
     cache_.FindPosition(pair.first);
   base::Time end = base::Time::Now();
-  perf_test::PrintResult("finding_in_cache", "", "",
-                         base::TimeDelta(end - start).InMillisecondsF(),
-                         "ms per batch", true);
+  auto reporter = SetUpReporter(kStoryBaseline);
+  reporter.AddResult(kMetricFindTimeMs, base::TimeDelta(end - start));
 }
 }  // namespace device
diff --git a/services/media_session/audio_focus_manager.cc b/services/media_session/audio_focus_manager.cc
index b5abcdf..76a079f 100644
--- a/services/media_session/audio_focus_manager.cc
+++ b/services/media_session/audio_focus_manager.cc
@@ -13,7 +13,7 @@
 #include "base/power_monitor/power_observer.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/unguessable_token.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/media_session/audio_focus_request.h"
 #include "services/media_session/public/cpp/features.h"
 #include "services/media_session/public/mojom/audio_focus.mojom.h"
@@ -64,13 +64,13 @@
       : identity_(source_id), observer_(std::move(observer)) {
     // Set a connection error handler so that we will remove observers that have
     // had an error / been closed.
-    observer_.set_connection_error_handler(base::BindOnce(
+    observer_.set_disconnect_handler(base::BindOnce(
         &AudioFocusManager::CleanupSourceObservers, base::Unretained(owner)));
   }
 
   ~SourceObserverHolder() = default;
 
-  bool is_valid() const { return !observer_.encountered_error(); }
+  bool is_valid() const { return observer_.is_connected(); }
 
   const base::UnguessableToken& identity() const { return identity_; }
 
@@ -84,7 +84,7 @@
 
  private:
   const base::UnguessableToken identity_;
-  mojom::AudioFocusObserverPtr observer_;
+  mojo::Remote<mojom::AudioFocusObserver> observer_;
 
   DISALLOW_COPY_AND_ASSIGN(SourceObserverHolder);
 };
diff --git a/services/network/cookie_manager.cc b/services/network/cookie_manager.cc
index c0f105a..5a08722 100644
--- a/services/network/cookie_manager.cc
+++ b/services/network/cookie_manager.cc
@@ -73,6 +73,11 @@
   cookie_store_->GetAllCookiesAsync(std::move(callback));
 }
 
+void CookieManager::GetAllCookiesWithAccessSemantics(
+    GetAllCookiesWithAccessSemanticsCallback callback) {
+  cookie_store_->GetAllCookiesWithAccessSemanticsAsync(std::move(callback));
+}
+
 void CookieManager::GetCookieList(const GURL& url,
                                   const net::CookieOptions& cookie_options,
                                   GetCookieListCallback callback) {
diff --git a/services/network/cookie_manager.h b/services/network/cookie_manager.h
index 47eadf97..9a76752 100644
--- a/services/network/cookie_manager.h
+++ b/services/network/cookie_manager.h
@@ -56,6 +56,8 @@
 
   // mojom::CookieManager
   void GetAllCookies(GetAllCookiesCallback callback) override;
+  void GetAllCookiesWithAccessSemantics(
+      GetAllCookiesWithAccessSemanticsCallback callback) override;
   void GetCookieList(const GURL& url,
                      const net::CookieOptions& cookie_options,
                      GetCookieListCallback callback) override;
diff --git a/services/network/cookie_manager_unittest.cc b/services/network/cookie_manager_unittest.cc
index 6794f77..39dfb0e 100644
--- a/services/network/cookie_manager_unittest.cc
+++ b/services/network/cookie_manager_unittest.cc
@@ -23,6 +23,7 @@
 #include "net/cookies/cookie_store_test_callbacks.h"
 #include "net/cookies/cookie_store_test_helpers.h"
 #include "net/cookies/cookie_util.h"
+#include "net/cookies/test_cookie_access_delegate.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "services/network/session_cleanup_cookie_store.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -82,6 +83,24 @@
     return cookies_out;
   }
 
+  std::vector<net::CanonicalCookie> GetAllCookiesWithAccessSemantics(
+      std::vector<net::CookieAccessSemantics>* access_semantics_list_out) {
+    base::RunLoop run_loop;
+    std::vector<net::CanonicalCookie> cookies_out;
+    cookie_service_->GetAllCookiesWithAccessSemantics(
+        base::BindLambdaForTesting(
+            [&run_loop, &cookies_out, access_semantics_list_out](
+                const std::vector<net::CanonicalCookie>& cookies,
+                const std::vector<net::CookieAccessSemantics>&
+                    access_semantics_list) {
+              cookies_out = cookies;
+              *access_semantics_list_out = access_semantics_list;
+              run_loop.Quit();
+            }));
+    run_loop.Run();
+    return cookies_out;
+  }
+
   std::vector<net::CanonicalCookie> GetCookieList(const GURL& url,
                                                   net::CookieOptions options) {
     base::RunLoop run_loop;
@@ -439,6 +458,75 @@
   EXPECT_EQ(net::COOKIE_PRIORITY_MEDIUM, cookies[3].Priority());
 }
 
+TEST_F(CookieManagerTest, GetAllCookiesWithAccessSemantics) {
+  auto delegate = std::make_unique<net::TestCookieAccessDelegate>();
+  delegate->SetExpectationForCookieDomain("domain1.test",
+                                          net::CookieAccessSemantics::UNKNOWN);
+  delegate->SetExpectationForCookieDomain("domain2.test",
+                                          net::CookieAccessSemantics::LEGACY);
+  delegate->SetExpectationForCookieDomain(
+      ".domainwithdot.test", net::CookieAccessSemantics::NONLEGACY);
+  cookie_store()->SetCookieAccessDelegate(std::move(delegate));
+
+  // Set some cookies for the test to play with.
+  // TODO(chlily): Because the order of the cookies with respect to the access
+  // semantics entries should match up, for the purposes of this test we need
+  // the cookies to sort in a predictable order. Since the longest path is
+  // first, we can manipulate the path attribute of each cookie set below to get
+  // them in the right order. This will have to change if CookieSorter ever
+  // starts sorting the cookies differently.
+
+  // UNKNOWN
+  EXPECT_TRUE(SetCanonicalCookie(
+      net::CanonicalCookie("A", "B", "domain1.test",
+                           "/this/path/is/the/longest/for/sorting/purposes",
+                           base::Time(), base::Time(), base::Time(),
+                           /*secure=*/false, /*httponly=*/false,
+                           net::CookieSameSite::NO_RESTRICTION,
+                           net::COOKIE_PRIORITY_MEDIUM),
+      "https", true));
+  // LEGACY
+  EXPECT_TRUE(SetCanonicalCookie(
+      net::CanonicalCookie(
+          "C", "D", "domain2.test", "/with/longer/path", base::Time(),
+          base::Time(), base::Time(), /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
+      "https", true));
+  // not set (UNKNOWN)
+  EXPECT_TRUE(SetCanonicalCookie(
+      net::CanonicalCookie(
+          "HttpOnly", "F", "domain3.test", "/with/path", base::Time(),
+          base::Time(), base::Time(), /*secure=*/false,
+          /*httponly=*/true, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
+      "https", true));
+  // NONLEGACY
+  EXPECT_TRUE(SetCanonicalCookie(
+      net::CanonicalCookie(
+          "Secure", "E", ".domainwithdot.test", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/true,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
+      "https", true));
+
+  std::vector<net::CookieAccessSemantics> access_semantics_list;
+  std::vector<net::CanonicalCookie> cookies =
+      service_wrapper()->GetAllCookiesWithAccessSemantics(
+          &access_semantics_list);
+
+  ASSERT_EQ(4u, cookies.size());
+  EXPECT_EQ(cookies.size(), access_semantics_list.size());
+  EXPECT_EQ("domain1.test", cookies[0].Domain());
+  EXPECT_EQ("domain2.test", cookies[1].Domain());
+  EXPECT_EQ("domain3.test", cookies[2].Domain());
+  EXPECT_EQ(".domainwithdot.test", cookies[3].Domain());
+
+  EXPECT_EQ(net::CookieAccessSemantics::UNKNOWN, access_semantics_list[0]);
+  EXPECT_EQ(net::CookieAccessSemantics::LEGACY, access_semantics_list[1]);
+  EXPECT_EQ(net::CookieAccessSemantics::UNKNOWN, access_semantics_list[2]);
+  EXPECT_EQ(net::CookieAccessSemantics::NONLEGACY, access_semantics_list[3]);
+}
+
 TEST_F(CookieManagerTest, GetCookieList) {
   // Set some cookies for the test to play with.
   EXPECT_TRUE(SetCanonicalCookie(
diff --git a/services/network/public/cpp/cookie_manager.typemap b/services/network/public/cpp/cookie_manager.typemap
index de9384bd..a365737 100644
--- a/services/network/public/cpp/cookie_manager.typemap
+++ b/services/network/public/cpp/cookie_manager.typemap
@@ -17,6 +17,7 @@
   "network.mojom.CookiePriority=::net::CookiePriority",
   "network.mojom.CookieSameSite=::net::CookieSameSite",
   "network.mojom.CookieSameSiteContext=::net::CookieOptions::SameSiteCookieContext",
+  "network.mojom.CookieAccessSemantics=::net::CookieAccessSemantics",
   "network.mojom.CookieOptions=::net::CookieOptions",
   "network.mojom.CanonicalCookie=::net::CanonicalCookie",
   "network.mojom.CookieInclusionStatusWarningReason=::net::CanonicalCookie::CookieInclusionStatus::WarningReason",
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.cc b/services/network/public/cpp/cookie_manager_mojom_traits.cc
index 6f3461ff..067058d8 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits.cc
+++ b/services/network/public/cpp/cookie_manager_mojom_traits.cc
@@ -86,6 +86,43 @@
   return false;
 }
 
+network::mojom::CookieAccessSemantics EnumTraits<
+    network::mojom::CookieAccessSemantics,
+    net::CookieAccessSemantics>::ToMojom(net::CookieAccessSemantics input) {
+  switch (input) {
+    case net::CookieAccessSemantics::UNKNOWN:
+      return network::mojom::CookieAccessSemantics::UNKNOWN;
+    case net::CookieAccessSemantics::NONLEGACY:
+      return network::mojom::CookieAccessSemantics::NONLEGACY;
+    case net::CookieAccessSemantics::LEGACY:
+      return network::mojom::CookieAccessSemantics::LEGACY;
+    default:
+      break;
+  }
+  NOTREACHED();
+  return static_cast<network::mojom::CookieAccessSemantics>(input);
+}
+
+bool EnumTraits<network::mojom::CookieAccessSemantics,
+                net::CookieAccessSemantics>::
+    FromMojom(network::mojom::CookieAccessSemantics input,
+              net::CookieAccessSemantics* output) {
+  switch (input) {
+    case network::mojom::CookieAccessSemantics::UNKNOWN:
+      *output = net::CookieAccessSemantics::UNKNOWN;
+      return true;
+    case network::mojom::CookieAccessSemantics::NONLEGACY:
+      *output = net::CookieAccessSemantics::NONLEGACY;
+      return true;
+    case network::mojom::CookieAccessSemantics::LEGACY:
+      *output = net::CookieAccessSemantics::LEGACY;
+      return true;
+    default:
+      break;
+  }
+  return false;
+}
+
 network::mojom::CookieInclusionStatusWarningReason
 EnumTraits<network::mojom::CookieInclusionStatusWarningReason,
            net::CanonicalCookie::CookieInclusionStatus::WarningReason>::
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.h b/services/network/public/cpp/cookie_manager_mojom_traits.h
index e5a345b..8730de54 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits.h
+++ b/services/network/public/cpp/cookie_manager_mojom_traits.h
@@ -29,6 +29,15 @@
 };
 
 template <>
+struct EnumTraits<network::mojom::CookieAccessSemantics,
+                  net::CookieAccessSemantics> {
+  static network::mojom::CookieAccessSemantics ToMojom(
+      net::CookieAccessSemantics input);
+  static bool FromMojom(network::mojom::CookieAccessSemantics input,
+                        net::CookieAccessSemantics* output);
+};
+
+template <>
 struct EnumTraits<network::mojom::CookieInclusionStatusWarningReason,
                   net::CanonicalCookie::CookieInclusionStatus::WarningReason> {
   static network::mojom::CookieInclusionStatusWarningReason ToMojom(
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc b/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
index 78dcf9b..b87238cd 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
+++ b/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
@@ -117,7 +117,8 @@
 TEST(CookieManagerTraitsTest, Roundtrips_CookieSameSite) {
   for (net::CookieSameSite cookie_state :
        {net::CookieSameSite::NO_RESTRICTION, net::CookieSameSite::LAX_MODE,
-        net::CookieSameSite::STRICT_MODE}) {
+        net::CookieSameSite::STRICT_MODE, net::CookieSameSite::EXTENDED_MODE,
+        net::CookieSameSite::UNSPECIFIED}) {
     net::CookieSameSite roundtrip;
     ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieSameSite>(cookie_state,
                                                                    &roundtrip));
@@ -125,6 +126,18 @@
   }
 }
 
+TEST(CookieManagerTraitsTest, Roundtrips_CookieAccessSemantics) {
+  for (net::CookieAccessSemantics access_semantics :
+       {net::CookieAccessSemantics::UNKNOWN,
+        net::CookieAccessSemantics::NONLEGACY,
+        net::CookieAccessSemantics::LEGACY}) {
+    net::CookieAccessSemantics roundtrip;
+    ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieAccessSemantics>(
+        access_semantics, &roundtrip));
+    EXPECT_EQ(access_semantics, roundtrip);
+  }
+}
+
 TEST(CookieManagerTraitsTest, Roundtrips_CookieSameSiteContext) {
   for (net::CookieOptions::SameSiteCookieContext context_state :
        {net::CookieOptions::SameSiteCookieContext::CROSS_SITE,
diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h
index 08c712c..f8cd1880 100644
--- a/services/network/public/cpp/resource_request.h
+++ b/services/network/public/cpp/resource_request.h
@@ -59,8 +59,52 @@
   GURL site_for_cookies;
   bool attach_same_site_cookies = false;
   bool update_first_party_url_on_redirect = false;
+
+  // |request_initiator| indicates the origin initiating the ResourceRequest.
+  //
+  // |request_initiator| is base::nullopt for browser-initiated requests (e.g.
+  // navigations initiated via omnibox or bookmarks, internal subrsource
+  // requests like fetching the SafeBrowsing data, etc.).
+  //
+  // For all requests initiated via web (both subresource requests and
+  // navigations), |request_initiator| is always set to the origin of the frame
+  // that has initiated the request.  This is true even if the request might
+  // have been initiated by an isolated world (e.g. from a content script of an
+  // extension, with its own, separate origin).  This needs to be true even if
+  // the request might be "proxied" in the browser process on behalf of a web
+  // origin (e.g. as is the case for PaymentRequest API).
+  //
+  // |request_initiator| is consulted in a variety of security features,
+  // including: calculating Sec-Fetch-Site request header, determining if the
+  // request should be subject to CORS, determining if CORB and/or CORP should
+  // block the response, determining if SameSite=strict cookies should be sent,
+  // etc.
+  //
+  // See also:
+  // - |isolated_world_origin|
+  // - URLLoaderFactoryParams::request_initiator_site_lock
   base::Optional<url::Origin> request_initiator;
+
+  // If this is a subresource request initiated from an isolated world (e.g.
+  // from a content script of a Chrome Extension), then |isolated_world_origin|
+  // indicates the origin of the isolated world.  Otherwise,
+  // |isolated_world_origin| is set to base::nullopt.
+  //
+  // Example #1: XHR initiated from a content script of chrome-extension://foo
+  // that was injected into a https://example.com web frame:
+  // - |request_initiator| is "https://example.com"
+  // - |isolated_world_origin| is "chrome-extension://foo"
+  //
+  // Example #2: XHR initiated from a Chrome Extension frame (e.g. from an
+  // extension background page):
+  // - |request_initiator| is "chrome-extension://foo"
+  // - |isolated_world_origin| is base::nullopt (this request is not associated
+  // with an isolated world)
+  //
+  // |isolated_world_origin| is consulted by OOR-CORS, to determine if this
+  // request might need to be exempt from CORS, based on OriginAccessList.
   base::Optional<url::Origin> isolated_world_origin;
+
   GURL referrer;
   net::URLRequest::ReferrerPolicy referrer_policy =
       net::URLRequest::NEVER_CLEAR_REFERRER;
diff --git a/services/network/public/mojom/cookie_manager.mojom b/services/network/public/mojom/cookie_manager.mojom
index 69903eb..c69b208 100644
--- a/services/network/public/mojom/cookie_manager.mojom
+++ b/services/network/public/mojom/cookie_manager.mojom
@@ -52,7 +52,6 @@
   LAX_MODE = 1,
   STRICT_MODE = 2,
   EXTENDED_MODE = 3,
-  // 4 is reserved: LAX_MODE_ALLOW_UNSAFE is not used here.
 };
 
 enum CookieSameSiteContext {
@@ -62,6 +61,15 @@
   SAME_SITE_STRICT
 };
 
+// What rules to apply when determining whether access to a particular cookie is
+// allowed.
+// Keep in sync with net/cookies/cookie_constants.h.
+enum CookieAccessSemantics {
+  UNKNOWN = -1,
+  NONLEGACY = 0,
+  LEGACY,
+};
+
 // Keep defaults here in sync with net/cookies/cookie_options.cc.
 struct CookieOptions {
   bool exclude_httponly = true;
@@ -215,6 +223,21 @@
   // on origin.  Should the returned cookies also be sorted by origin?
   GetAllCookies() => (array<CanonicalCookie> cookies);
 
+  // Get all the cookies known to the service.
+  // Returned cookie list is sorted first by path length (longest first)
+  // and second by creation time.
+  // Additionally get a list of the CookieAccessSemantics that applies to each,
+  // if known. The |access_semantics_list| is guaranteed to be the same length
+  // as |cookies|, with each element in |cookies| having the access semantics
+  // which is given by the same index in |access_semantics_list|. If this method
+  // is not implemented in the underlying CookieStore, the returned
+  // |access_semantics_list| will just contain all UNKNOWNs. If it is
+  // supported, the access semantics values will have been determined by
+  // querying the CookieStore's CookieAccessDelegate.
+  GetAllCookiesWithAccessSemantics()
+      => (array<CanonicalCookie> cookies,
+          array<CookieAccessSemantics> access_semantics_list);
+
   // Get all cookies for the specified URL and cookie options.
   // Returned cookie list is sorted first by path length (longest first)
   // and second by creation time. If the |return_excluded_cookies| option is set
diff --git a/services/network/public/mojom/ssl_config.mojom b/services/network/public/mojom/ssl_config.mojom
index 9560ae1..b97a701 100644
--- a/services/network/public/mojom/ssl_config.mojom
+++ b/services/network/public/mojom/ssl_config.mojom
@@ -20,6 +20,10 @@
   bool sha1_local_anchors_enabled = false;
   bool symantec_enforcement_disabled = false;
 
+  // If true, enables TLS 1.3 downgrade hardening for connections using local
+  // trust anchors. (Hardening for known roots is always enabled.)
+  bool tls13_hardening_for_local_anchors_enabled = false;
+
   // SSL 2.0 and 3.0 are not supported. Note these lines must be kept in sync
   // with net/ssl/ssl_config.cc.
   SSLVersion version_min = kTLS1;
diff --git a/services/network/ssl_config_service_mojo_unittest.cc b/services/network/ssl_config_service_mojo_unittest.cc
index d45fafc..e7b1199 100644
--- a/services/network/ssl_config_service_mojo_unittest.cc
+++ b/services/network/ssl_config_service_mojo_unittest.cc
@@ -430,6 +430,16 @@
   RunConversionTests(*mojo_config, expected_net_config);
 }
 
+TEST_F(NetworkServiceSSLConfigServiceTest, InitialConfigTLS13Hardening) {
+  net::SSLContextConfig expected_net_config;
+  expected_net_config.tls13_hardening_for_local_anchors_enabled = true;
+
+  mojom::SSLConfigPtr mojo_config = mojom::SSLConfig::New();
+  mojo_config->tls13_hardening_for_local_anchors_enabled = true;
+
+  RunConversionTests(*mojo_config, expected_net_config);
+}
+
 TEST_F(NetworkServiceSSLConfigServiceTest, CanShareConnectionWithClientCerts) {
   // Create a default NetworkContext and test that
   // CanShareConnectionWithClientCerts returns false.
diff --git a/services/network/ssl_config_type_converter.cc b/services/network/ssl_config_type_converter.cc
index 125f3e5..d69112d 100644
--- a/services/network/ssl_config_type_converter.cc
+++ b/services/network/ssl_config_type_converter.cc
@@ -34,6 +34,8 @@
   DCHECK_LE(net_config.version_min, net_config.version_max);
 
   net_config.disabled_cipher_suites = mojo_config->disabled_cipher_suites;
+  net_config.tls13_hardening_for_local_anchors_enabled =
+      mojo_config->tls13_hardening_for_local_anchors_enabled;
   return net_config;
 }
 
diff --git a/services/network/test/test_cookie_manager.h b/services/network/test/test_cookie_manager.h
index e9ab7f7d..fc197a1 100644
--- a/services/network/test/test_cookie_manager.h
+++ b/services/network/test/test_cookie_manager.h
@@ -27,6 +27,8 @@
                           const net::CookieOptions& cookie_options,
                           SetCanonicalCookieCallback callback) override;
   void GetAllCookies(GetAllCookiesCallback callback) override {}
+  void GetAllCookiesWithAccessSemantics(
+      GetAllCookiesWithAccessSemanticsCallback callback) override {}
   void GetCookieList(const GURL& url,
                      const net::CookieOptions& cookie_options,
                      GetCookieListCallback callback) override {}
diff --git a/services/resource_coordinator/public/mojom/BUILD.gn b/services/resource_coordinator/public/mojom/BUILD.gn
index 17ea149..91170ef 100644
--- a/services/resource_coordinator/public/mojom/BUILD.gn
+++ b/services/resource_coordinator/public/mojom/BUILD.gn
@@ -9,8 +9,6 @@
   macro_prefix = "RESOURCE_COORDINATOR_PUBLIC_MOJOM"
 
   sources = [
-    "coordination_unit.mojom",
-    "lifecycle.mojom",
     "memory_instrumentation/constants.mojom",
     "memory_instrumentation/memory_instrumentation.mojom",
     "resource_coordinator_service.mojom",
diff --git a/services/resource_coordinator/public/mojom/OWNERS b/services/resource_coordinator/public/mojom/OWNERS
index 5c3a6ac4..08850f4 100644
--- a/services/resource_coordinator/public/mojom/OWNERS
+++ b/services/resource_coordinator/public/mojom/OWNERS
@@ -1,4 +1,2 @@
-per-file BUILD.gn=file://services/resource_coordinator/memory_instrumentation/OWNERS
-
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/services/service_manager/sandbox/linux/sandbox_linux.cc b/services/service_manager/sandbox/linux/sandbox_linux.cc
index f6231d4..b637c4f1 100644
--- a/services/service_manager/sandbox/linux/sandbox_linux.cc
+++ b/services/service_manager/sandbox/linux/sandbox_linux.cc
@@ -293,12 +293,18 @@
   if (hook)
     CHECK(std::move(hook).Run(options));
 
+  // If we allow threads *and* have multiple threads, try to use TSYNC.
+  sandbox::SandboxBPF::SeccompLevel seccomp_level =
+      options.allow_threads_during_sandbox_init && !IsSingleThreaded()
+          ? sandbox::SandboxBPF::SeccompLevel::MULTI_THREADED
+          : sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED;
+
   // If the kernel supports the sandbox, and if the command line says we
   // should enable it, enable it or die.
   std::unique_ptr<BPFBasePolicy> policy =
       SandboxSeccompBPF::PolicyForSandboxType(sandbox_type, options);
-  SandboxSeccompBPF::StartSandboxWithExternalPolicy(std::move(policy),
-                                                    OpenProc(proc_fd_));
+  SandboxSeccompBPF::StartSandboxWithExternalPolicy(
+      std::move(policy), OpenProc(proc_fd_), seccomp_level);
   SandboxSeccompBPF::RunSandboxSanityChecks(sandbox_type, options);
   seccomp_bpf_started_ = true;
   LogSandboxStarted("seccomp-bpf");
@@ -329,9 +335,13 @@
       base::BindOnce(&SandboxLinux::CheckForBrokenPromises,
                      base::Unretained(this), sandbox_type));
 
-  // No matter what, it's always an error to call InitializeSandbox() after
-  // threads have been created.
-  if (!IsSingleThreaded()) {
+  const bool has_threads = !IsSingleThreaded();
+
+  // For now, restrict the |options.allow_threads_during_sandbox_init| option to
+  // the GPU process
+  DCHECK(process_type == switches::kGpuProcess ||
+         !options.allow_threads_during_sandbox_init);
+  if (has_threads && !options.allow_threads_during_sandbox_init) {
     std::string error_message =
         "InitializeSandbox() called with multiple threads in process " +
         process_type + ".";
@@ -340,13 +350,6 @@
     if (IsRunningTSAN())
       return false;
 
-#if defined(OS_CHROMEOS)
-    if (base::SysInfo::IsRunningOnChromeOS() &&
-        process_type == switches::kGpuProcess) {
-      error_message += " This error can be safely ignored in VMTests.";
-    }
-#endif
-
     // The GPU process is allowed to call InitializeSandbox() with threads.
     bool sandbox_failure_fatal = process_type != switches::kGpuProcess;
     // This can be disabled with the '--gpu-sandbox-failures-fatal' flag.
@@ -371,21 +374,31 @@
     }
   }
 
-  // Only one thread is running, pre-initialize if not already done.
+  // At this point we are either single threaded, or we won't be engaging the
+  // semantic layer of the sandbox and we won't care if there are file
+  // descriptors left open.
+
+  // Pre-initialize if not already done.
   if (!pre_initialized_)
     PreinitializeSandbox();
 
-  // Turn on the namespace sandbox if the zygote hasn't done so already.
+  // Turn on the namespace sandbox if our caller wants it (and the zygote hasn't
+  // done so already).
   if (options.engage_namespace_sandbox)
     EngageNamespaceSandbox(false /* from_zygote */);
 
-  CHECK(!HasOpenDirectories())
+  // Check for open directories, which can break the semantic sandbox layer. In
+  // some cases the caller doesn't want to enable the semantic sandbox layer,
+  // and this CHECK should be skipped. In this case, the caller should unset
+  // |options.check_for_open_directories|.
+  CHECK(!options.check_for_open_directories || !HasOpenDirectories())
       << "InitializeSandbox() called after unexpected directories have been "
       << "opened. This breaks the security of the setuid sandbox.";
 
   sandbox::InitLibcLocaltimeFunctions();
 
   // Attempt to limit the future size of the address space of the process.
+  // Fine to call with multiple threads as we don't use RLIMIT_STACK.
   int error = 0;
   const bool limited_as = LimitAddressSpace(&error);
   if (error) {
@@ -448,6 +461,7 @@
   // other memory-hungry attack modes.
 
   rlim_t process_data_size_limit = GetProcessDataSizeLimit(sandbox_type);
+  // Fine to call with multiple threads as we don't use RLIMIT_STACK.
   *error = sandbox::ResourceLimits::Lower(RLIMIT_DATA, process_data_size_limit);
 
   // Cache the resource limit before turning on the sandbox.
@@ -510,6 +524,11 @@
 
 bool SandboxLinux::EngageNamespaceSandboxInternal(bool from_zygote) {
   CHECK(pre_initialized_);
+  CHECK(IsSingleThreaded())
+      << "The process cannot have multiple threads when engaging the namespace "
+         "sandbox, because the thread engaging the sandbox cannot ensure that "
+         "other threads close all their open directories.";
+
   if (from_zygote) {
     // Check being in a new PID namespace created by the namespace sandbox and
     // being the init process.
diff --git a/services/service_manager/sandbox/linux/sandbox_linux.h b/services/service_manager/sandbox/linux/sandbox_linux.h
index 5b6501a..597ea53 100644
--- a/services/service_manager/sandbox/linux/sandbox_linux.h
+++ b/services/service_manager/sandbox/linux/sandbox_linux.h
@@ -99,6 +99,16 @@
     // be done so again. Set to true to indicate that there isn't a zygote
     // for this process and the step is to be performed here explicitly.
     bool engage_namespace_sandbox = false;
+
+    // Allow starting the sandbox with multiple threads already running. This
+    // will enable TSYNC for seccomp-BPF, which syncs the seccomp-BPF policy
+    // across all running threads.
+    bool allow_threads_during_sandbox_init = false;
+
+    // Enables the CHECK for open directories. The open directory check is only
+    // useful for the chroot jail (from the semantic layer of the sandbox), and
+    // can safely be disabled if we are only enabling the seccomp-BPF layer.
+    bool check_for_open_directories = true;
   };
 
   // Callers can provide this hook to run code right before the policy
@@ -176,9 +186,11 @@
   // be used directly.
   sandbox::SetuidSandboxClient* setuid_sandbox_client() const;
 
-  // Check the policy and eventually start the seccomp-bpf sandbox. This should
-  // never be called with threads started. If we detect that threads have
-  // started we will crash.
+  // Check the policy and eventually start the seccomp-bpf sandbox. Fine to be
+  // called with threads, as long as
+  // |options.allow_threads_during_sandbox_init| is true and the kernel
+  // supports seccomp's TSYNC feature. If TSYNC is not available we treat
+  // multiple threads as a fatal error.
   bool StartSeccompBPF(service_manager::SandboxType sandbox_type,
                        PreSandboxHook hook,
                        const Options& options);
diff --git a/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.cc b/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.cc
index efd86b8..94de83a8 100644
--- a/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.cc
+++ b/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.cc
@@ -225,7 +225,8 @@
 
 bool SandboxSeccompBPF::StartSandboxWithExternalPolicy(
     std::unique_ptr<sandbox::bpf_dsl::Policy> policy,
-    base::ScopedFD proc_fd) {
+    base::ScopedFD proc_fd,
+    sandbox::SandboxBPF::SeccompLevel seccomp_level) {
 #if BUILDFLAG(USE_SECCOMP_BPF)
   if (IsSeccompBPFDesired() && SupportsSandbox()) {
     CHECK(policy);
@@ -236,7 +237,7 @@
     // doing so does not stop the sandbox.
     SandboxBPF sandbox(std::move(policy));
     sandbox.SetProcFd(std::move(proc_fd));
-    CHECK(sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED));
+    CHECK(sandbox.StartSandbox(seccomp_level));
     return true;
   }
 #endif  // BUILDFLAG(USE_SECCOMP_BPF)
diff --git a/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.h b/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.h
index 7170f49d..4da095a 100644
--- a/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.h
+++ b/services/service_manager/sandbox/linux/sandbox_seccomp_bpf_linux.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
 #include "services/service_manager/sandbox/export.h"
 #include "services/service_manager/sandbox/linux/bpf_base_policy_linux.h"
 #include "services/service_manager/sandbox/sandbox_type.h"
@@ -60,7 +61,9 @@
   // external policy.
   static bool StartSandboxWithExternalPolicy(
       std::unique_ptr<sandbox::bpf_dsl::Policy> policy,
-      base::ScopedFD proc_fd);
+      base::ScopedFD proc_fd,
+      sandbox::SandboxBPF::SeccompLevel seccomp_level =
+          sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED);
 
   // The "baseline" policy can be a useful base to build a sandbox policy.
   static std::unique_ptr<sandbox::bpf_dsl::Policy> GetBaselinePolicy();
diff --git a/services/tracing/perfetto/consumer_host.cc b/services/tracing/perfetto/consumer_host.cc
index ea9034e9..189a081 100644
--- a/services/tracing/perfetto/consumer_host.cc
+++ b/services/tracing/perfetto/consumer_host.cc
@@ -21,6 +21,7 @@
 #include "base/trace_event/trace_log.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/wait.h"
 #include "services/tracing/perfetto/json_trace_exporter.h"
@@ -479,12 +480,12 @@
 }
 
 // static
-void ConsumerHost::BindConsumerRequest(
+void ConsumerHost::BindConsumerReceiver(
     PerfettoService* service,
-    mojom::ConsumerHostRequest request,
+    mojo::PendingReceiver<mojom::ConsumerHost> receiver,
     const service_manager::BindSourceInfo& source_info) {
-  mojo::MakeStrongBinding(std::make_unique<ConsumerHost>(service),
-                          std::move(request));
+  mojo::MakeSelfOwnedReceiver(std::make_unique<ConsumerHost>(service),
+                              std::move(receiver));
 }
 
 ConsumerHost::ConsumerHost(PerfettoService* service) : service_(service) {
diff --git a/services/tracing/perfetto/consumer_host.h b/services/tracing/perfetto/consumer_host.h
index 088ab889..b9afbc2 100644
--- a/services/tracing/perfetto/consumer_host.h
+++ b/services/tracing/perfetto/consumer_host.h
@@ -40,9 +40,9 @@
 // to act as a Perfetto consumer.
 class ConsumerHost : public perfetto::Consumer, public mojom::ConsumerHost {
  public:
-  static void BindConsumerRequest(
+  static void BindConsumerReceiver(
       PerfettoService* service,
-      mojom::ConsumerHostRequest request,
+      mojo::PendingReceiver<mojom::ConsumerHost> receiver,
       const service_manager::BindSourceInfo& source_info);
 
   class StreamWriter;
diff --git a/services/tracing/public/cpp/BUILD.gn b/services/tracing/public/cpp/BUILD.gn
index 9ce73f7..75cc5fa 100644
--- a/services/tracing/public/cpp/BUILD.gn
+++ b/services/tracing/public/cpp/BUILD.gn
@@ -34,6 +34,8 @@
       "perfetto/dummy_producer.cc",
       "perfetto/dummy_producer.h",
       "perfetto/interning_index.h",
+      "perfetto/java_heap_profiler/java_heap_profiler.cc",
+      "perfetto/java_heap_profiler/java_heap_profiler.h",
       "perfetto/perfetto_config.cc",
       "perfetto/perfetto_config.h",
       "perfetto/perfetto_producer.cc",
diff --git a/services/tracing/public/cpp/perfetto/interning_index.h b/services/tracing/public/cpp/perfetto/interning_index.h
index d9a7cd2..525cdb6 100644
--- a/services/tracing/public/cpp/perfetto/interning_index.h
+++ b/services/tracing/public/cpp/perfetto/interning_index.h
@@ -5,11 +5,11 @@
 #ifndef SERVICES_TRACING_PUBLIC_CPP_PERFETTO_INTERNING_INDEX_H_
 #define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_INTERNING_INDEX_H_
 
-#include <array>
 #include <cstdint>
 #include <tuple>
 
 #include "base/component_export.h"
+#include "base/containers/mru_cache.h"
 
 namespace tracing {
 
@@ -17,7 +17,7 @@
 using InterningID = uint32_t;
 
 struct COMPONENT_EXPORT(TRACING_CPP) InterningIndexEntry {
-  InterningID id = 0;
+  InterningID id;
 
   // Whether the entry was emitted since the last reset of emitted state. If
   // |false|, the sink should (re)emit the entry in the current TracePacket.
@@ -25,80 +25,29 @@
   // We don't remove entries on reset of emitted state, so that we can continue
   // to use their original IDs and avoid unnecessarily incrementing the ID
   // counter.
-  bool was_emitted = false;
+  bool was_emitted;
 };
 
 // Interning index that associates interned values with interning IDs. It can
 // track entries of different types within the same ID space, e.g. so that both
 // copied strings and pointers to static strings can co-exist in the same index.
-//
-// The index will cache up to |N| values per ValueType after which it will start
-// replacing them in a FIFO basis. N must be a power of 2 for performance
-// reasons.
-template <size_t N, typename... ValueTypes>
+// Uses base::MRUCaches to track the ID associations while enforcing an upper
+// bound on the index size.
+template <typename... ValueTypes>
 class COMPONENT_EXPORT(TRACING_CPP) InterningIndex {
  public:
-  // IndexCache is just a pair of std::arrays which arg kept in sync with each
-  // other. This has an advantage over a std::array<pairs> since we can load a
-  // bunch of keys to search in one cache line without loading values.
   template <typename ValueType>
-  class IndexCache {
-   public:
-    IndexCache() {
-      // Assert that N is a power of two. This allows the "% N" in Insert() to
-      // compile to a bunch of bit shifts which improves performance over an
-      // arbitrary modulo division.
-      static_assert(
-          N && ((N & (N - 1)) == 0),
-          "InterningIndex requires that the cache size be a power of 2.");
-    }
+  using IndexCache = base::MRUCache<ValueType, InterningIndexEntry>;
 
-    void Clear() {
-      for (auto& val : keys_) {
-        val = ValueType{};
-      }
-    }
-
-    typename std::array<InterningIndexEntry, N>::iterator Find(
-        const ValueType& value) {
-      auto it = std::find(keys_.begin(), keys_.end(), value);
-      // If the find above returns it == keys_.end(), then (it - keys_.begin())
-      // will equal keys_.size() which is equal to values_.size(). So
-      // values_.begin() + values_size() will be values_.end() and we've
-      // returned the correct value. This saves us checking a conditional in
-      // this function.
-      return values_.begin() + (it - keys_.begin());
-    }
-
-    typename std::array<InterningIndexEntry, N>::iterator Insert(
-        const ValueType& key,
-        InterningIndexEntry&& value) {
-      size_t new_position = current_index_++ % N;
-      keys_[new_position] = key;
-      values_[new_position] = std::move(value);
-      return values_.begin() + new_position;
-    }
-
-    typename std::array<InterningIndexEntry, N>::iterator begin() {
-      return values_.begin();
-    }
-    typename std::array<InterningIndexEntry, N>::iterator end() {
-      return values_.end();
-    }
-
-   private:
-    size_t current_index_ = 0;
-    std::array<ValueType, N> keys_{{}};
-    std::array<InterningIndexEntry, N> values_{{}};
-  };
-
-  // Construct a new index with caches for each of the ValueTypes. Every cache
-  // is |N| elements.
+  // Construct a new index with caches for each of the ValueTypes. The cache
+  // size for the n-th ValueType will be limited to max_entry_counts[n] entries.
   //
-  // For example, to construct an index containing at most 1024 char* pointers
-  // and 1024 std::string objects:
-  //     InterningIndex<1024, char*, std::string> index;
-  InterningIndex() = default;
+  // For example, to construct an index containing at most 1000 char* pointers
+  // and 100 std::string objects:
+  //     InterningIndex<char*, std::string> index(1000, 100);
+  template <typename... SizeType>
+  InterningIndex(SizeType... max_entry_counts)
+      : entry_caches_(max_entry_counts...) {}
 
   // Returns the entry for the given interned |value|, adding it to the index if
   // it didn't exist previously or was evicted from the index. Entries may be
@@ -111,14 +60,14 @@
   InterningIndexEntry LookupOrAdd(const ValueType& value) {
     IndexCache<ValueType>& cache =
         std::get<IndexCache<ValueType>>(entry_caches_);
-    auto it = cache.Find(value);
+    auto it = cache.Get(value);
     if (it == cache.end()) {
-      it = cache.Insert(value, InterningIndexEntry{next_id_++, false});
+      it = cache.Put(value, InterningIndexEntry{next_id_++, false});
     }
-    bool was_emitted = it->was_emitted;
+    bool was_emitted = it->second.was_emitted;
     // The caller will (re)emit the entry, so mark it as emitted.
-    it->was_emitted = true;
-    return InterningIndexEntry{it->id, was_emitted};
+    it->second.was_emitted = true;
+    return InterningIndexEntry{it->second.id, was_emitted};
   }
 
   // Marks all entries as "not emitted", so that they will be reemitted when
@@ -154,7 +103,7 @@
       cache.Clear();
     } else {
       for (auto& entry : cache) {
-        entry.was_emitted = false;
+        entry.second.was_emitted = false;
       }
     }
   }
diff --git a/services/tracing/public/cpp/perfetto/java_heap_profiler/java_heap_profiler.cc b/services/tracing/public/cpp/perfetto/java_heap_profiler/java_heap_profiler.cc
new file mode 100644
index 0000000..a787d76
--- /dev/null
+++ b/services/tracing/public/cpp/perfetto/java_heap_profiler/java_heap_profiler.cc
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/tracing/public/cpp/perfetto/java_heap_profiler/java_heap_profiler.h"
+
+#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
+
+namespace tracing {
+
+JavaHeapProfiler::JavaHeapProfiler()
+    : DataSourceBase(mojom::kJavaHeapProfilerSourceName) {}
+
+// static
+JavaHeapProfiler* JavaHeapProfiler::GetInstance() {
+  static base::NoDestructor<JavaHeapProfiler> instance;
+  return instance.get();
+}
+
+void JavaHeapProfiler::StartTracing(
+    PerfettoProducer* producer,
+    const perfetto::DataSourceConfig& data_source_config) {}
+
+void JavaHeapProfiler::StopTracing(base::OnceClosure stop_complete_callback) {
+  producer_ = nullptr;
+  std::move(stop_complete_callback).Run();
+}
+
+void JavaHeapProfiler::Flush(base::RepeatingClosure flush_complete_callback) {
+  flush_complete_callback.Run();
+}
+}  // namespace tracing
diff --git a/services/tracing/public/cpp/perfetto/java_heap_profiler/java_heap_profiler.h b/services/tracing/public/cpp/perfetto/java_heap_profiler/java_heap_profiler.h
new file mode 100644
index 0000000..c35f233c
--- /dev/null
+++ b/services/tracing/public/cpp/perfetto/java_heap_profiler/java_heap_profiler.h
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_TRACING_PUBLIC_CPP_PERFETTO_JAVA_HEAP_PROFILER_JAVA_HEAP_PROFILER_H_
+#define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_JAVA_HEAP_PROFILER_JAVA_HEAP_PROFILER_H_
+
+#include "base/component_export.h"
+#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
+
+namespace tracing {
+
+// This is a Java heap profiler on Android that provides heap dumps to
+// tracing The profiler is enabled based on
+// DISABLED_BY_DEFAULT("java_heap_profiler") category.
+class COMPONENT_EXPORT(TRACING_CPP) JavaHeapProfiler
+    : public PerfettoTracedProcess::DataSourceBase {
+ public:
+  static JavaHeapProfiler* GetInstance();
+
+  JavaHeapProfiler();
+
+  // PerfettoTracedProcess::DataSourceBase implementation:
+  void StartTracing(
+      PerfettoProducer* producer,
+      const perfetto::DataSourceConfig& data_source_config) override;
+  void StopTracing(base::OnceClosure stop_complete_callback) override;
+  void Flush(base::RepeatingClosure flush_complete_callback) override;
+};
+}  // namespace tracing
+
+#endif  // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_JAVA_HEAP_PROFILER_JAVA_HEAP_PROFILER_H_
diff --git a/services/tracing/public/cpp/perfetto/perfetto_config.cc b/services/tracing/public/cpp/perfetto/perfetto_config.cc
index 32ef78e9..8bbfa038 100644
--- a/services/tracing/public/cpp/perfetto/perfetto_config.cc
+++ b/services/tracing/public/cpp/perfetto/perfetto_config.cc
@@ -124,6 +124,13 @@
                         chrome_config_string, privacy_filtering_enabled);
   }
 
+  if (chrome_config.IsCategoryGroupEnabled(
+          TRACE_DISABLED_BY_DEFAULT("java_heap_profiler"))) {
+    AddDataSourceConfig(&perfetto_config,
+                        tracing::mojom::kJavaHeapProfilerSourceName,
+                        chrome_config_string, privacy_filtering_enabled);
+  }
+
   return perfetto_config;
 }
 
diff --git a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
index 2ca0914..a484a2d 100644
--- a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
+++ b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
@@ -169,6 +169,12 @@
     : ThreadLocalEventSink(std::move(trace_writer),
                            session_id,
                            disable_interning),
+      // TODO(eseckler): Tune these values experimentally.
+      interned_event_categories_(1000),
+      interned_event_names_(1000, 100),
+      interned_annotation_names_(1000, 100),
+      interned_source_locations_(1000),
+      interned_log_message_bodies_(100),
       process_id_(TraceLog::GetInstance()->process_id()),
       thread_id_(static_cast<int>(base::PlatformThread::CurrentId())),
       privacy_filtering_enabled_(proto_writer_filtering_enabled) {
diff --git a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h
index 9a4b90a..52a071a 100644
--- a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h
+++ b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h
@@ -69,13 +69,12 @@
 
   // TODO(eseckler): Make it possible to register new indexes for use from
   // TRACE_EVENT macros.
-  // TODO(eseckler): Tune the cache sizes experimentally.
-  InterningIndex<1024, const char*> interned_event_categories_;
-  InterningIndex<1024, const char*, std::string> interned_event_names_;
-  InterningIndex<1024, const char*, std::string> interned_annotation_names_;
-  InterningIndex<1024, std::tuple<const char*, const char*, int>>
+  InterningIndex<const char*> interned_event_categories_;
+  InterningIndex<const char*, std::string> interned_event_names_;
+  InterningIndex<const char*, std::string> interned_annotation_names_;
+  InterningIndex<std::tuple<const char*, const char*, int>>
       interned_source_locations_;
-  InterningIndex<128, std::string> interned_log_message_bodies_;
+  InterningIndex<std::string> interned_log_message_bodies_;
 
   static std::atomic<uint32_t> incremental_state_reset_id_;
 
diff --git a/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h b/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h
index 6d71f9e..7d0bf610 100644
--- a/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h
+++ b/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h
@@ -78,15 +78,14 @@
     const base::PlatformThreadId sampled_thread_id_;
     base::Lock trace_writer_lock_;
     std::unique_ptr<perfetto::TraceWriter> trace_writer_;
-    InterningIndex<1024, size_t> interned_callstacks_{};
-    InterningIndex<1024,
-                   std::pair<std::string, std::string>,
+    InterningIndex<size_t> interned_callstacks_{1000};
+    InterningIndex<std::pair<std::string, std::string>,
                    std::pair<uintptr_t, std::string>>
-        interned_frames_{};
-    InterningIndex<1024, std::string> interned_frame_names_{};
-    InterningIndex<1024, std::string> interned_module_names_{};
-    InterningIndex<1024, std::string> interned_module_ids_{};
-    InterningIndex<1024, uintptr_t> interned_modules_{};
+        interned_frames_{1000, 1000};
+    InterningIndex<std::string> interned_frame_names_{1000};
+    InterningIndex<std::string> interned_module_names_{1000};
+    InterningIndex<std::string> interned_module_ids_{1000};
+    InterningIndex<uintptr_t> interned_modules_{1000};
     bool reset_incremental_state_ = true;
     uint32_t last_incremental_state_reset_id_ = 0;
     int32_t last_emitted_process_priority_ = -1;
diff --git a/services/tracing/public/mojom/perfetto_service.mojom b/services/tracing/public/mojom/perfetto_service.mojom
index 604d229..78c8e35 100644
--- a/services/tracing/public/mojom/perfetto_service.mojom
+++ b/services/tracing/public/mojom/perfetto_service.mojom
@@ -10,6 +10,7 @@
 const string kSystemTraceDataSourceName = "org.chromium.trace_system";
 const string kArcTraceDataSourceName = "org.chromium.trace_arc";
 const string kSamplerProfilerSourceName = "org.chromium.sampler_profiler";
+const string kJavaHeapProfilerSourceName = "org.chromium.java_heap_profiler";
 
 // Brief description of the flow: There's a per-process ProducerClient which
 // connects to the central PerfettoService and establishes a two-way connection
diff --git a/services/tracing/tracing_service.cc b/services/tracing/tracing_service.cc
index 569b345..c3428a7 100644
--- a/services/tracing/tracing_service.cc
+++ b/services/tracing/tracing_service.cc
@@ -189,7 +189,7 @@
                           base::Unretained(tracing_coordinator_.get())));
 
   registry_.AddInterface(
-      base::BindRepeating(&ConsumerHost::BindConsumerRequest,
+      base::BindRepeating(&ConsumerHost::BindConsumerReceiver,
                           base::Unretained(PerfettoService::GetInstance())));
 
   service_listener_ = std::make_unique<ServiceListener>(
diff --git a/services/viz/public/cpp/compositing/mojom_traits_perftest.cc b/services/viz/public/cpp/compositing/mojom_traits_perftest.cc
index 84f7ef16..537e95d 100644
--- a/services/viz/public/cpp/compositing/mojom_traits_perftest.cc
+++ b/services/viz/public/cpp/compositing/mojom_traits_perftest.cc
@@ -19,7 +19,7 @@
 #include "services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h"
 #include "services/viz/public/cpp/compositing/surface_id_mojom_traits.h"
 #include "services/viz/public/mojom/compositing/compositor_frame.mojom.h"
-#include "testing/perf/perf_test.h"
+#include "testing/perf/perf_result_reporter.h"
 #include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
 #include "ui/gfx/mojom/selection_bound_mojom_traits.h"
 #include "ui/latency/mojom/latency_info_mojom_traits.h"
@@ -33,10 +33,37 @@
 
 enum class UseSingleSharedQuadState { YES, NO };
 
+constexpr char kMetricPrefixVizSerialization[] = "VizSerialization.";
+constexpr char kMetricStructDeserializationTimeUs[] =
+    "StructTraits_min_frame_deserialization_time";
+constexpr char kMetricStructDeserializationThroughputRunsPerS[] =
+    "StructTraits_deserialization_throughput";
+constexpr char kMetricStructSerializationTimeUs[] =
+    "StructTraits_min_frame_serialization_time";
+constexpr char kMetricStructSerializationThroughputRunsPerS[] =
+    "StructTraits_serialization_throughput";
+
+perf_test::PerfResultReporter SetUpReporter(
+    const std::string& story,
+    UseSingleSharedQuadState single_sqs) {
+  std::string story_suffix = single_sqs == UseSingleSharedQuadState::YES
+                                 ? "_per_render_pass_shared_quad_state"
+                                 : "_per_quad_shared_quad_state";
+  perf_test::PerfResultReporter reporter(kMetricPrefixVizSerialization,
+                                         story + story_suffix);
+  reporter.RegisterImportantMetric(kMetricStructDeserializationTimeUs, "us");
+  reporter.RegisterImportantMetric(
+      kMetricStructDeserializationThroughputRunsPerS, "runs/s");
+  reporter.RegisterImportantMetric(kMetricStructSerializationTimeUs, "us");
+  reporter.RegisterImportantMetric(kMetricStructSerializationThroughputRunsPerS,
+                                   "runs/s");
+  return reporter;
+}
+
 class VizSerializationPerfTest : public testing::Test {
  protected:
   static void RunDeserializationTestStructTraits(
-      const std::string& test_name,
+      const std::string& story,
       const CompositorFrame& frame,
       UseSingleSharedQuadState single_sqs) {
     mojo::Message message = mojom::CompositorFrame::SerializeAsMessage(&frame);
@@ -68,23 +95,15 @@
       start = now;
     }
 
-    perf_test::PrintResult(
-        "StructTraits deserialization min_frame_deserialization_time",
-        single_sqs == UseSingleSharedQuadState::YES
-            ? "_per_render_pass_shared_quad_state"
-            : "_per_quad_shared_quad_state",
-        test_name, min_time.InMillisecondsF() / kTimeCheckInterval * 1000, "us",
-        true);
-    perf_test::PrintResult(
-        "StructTraits deserialization: num runs in 2 seconds",
-        single_sqs == UseSingleSharedQuadState::YES
-            ? "_per_render_pass_shared_quad_state"
-            : "_per_quad_shared_quad_state",
-        test_name, count, "runs/s", true);
+    auto reporter = SetUpReporter(story, single_sqs);
+    reporter.AddResult(kMetricStructDeserializationTimeUs,
+                       min_time.InMicrosecondsF() / kTimeCheckInterval);
+    reporter.AddResult(kMetricStructDeserializationThroughputRunsPerS,
+                       count * 1000 / kTimeLimitMillis);
   }
 
   static void RunSerializationTestStructTraits(
-      const std::string& test_name,
+      const std::string& story,
       const CompositorFrame& frame,
       UseSingleSharedQuadState single_sqs) {
     for (int i = 0; i < kNumWarmupRuns; ++i) {
@@ -113,21 +132,14 @@
       start = now;
     }
 
-    perf_test::PrintResult(
-        "StructTraits serialization min_frame_serialization_time",
-        single_sqs == UseSingleSharedQuadState::YES
-            ? "_per_render_pass_shared_quad_state"
-            : "_per_quad_shared_quad_state",
-        test_name, min_time.InMillisecondsF() / kTimeCheckInterval * 1000, "us",
-        true);
-    perf_test::PrintResult("StructTraits serialization: num runs in 2 seconds",
-                           single_sqs == UseSingleSharedQuadState::YES
-                               ? "_per_render_pass_shared_quad_state"
-                               : "_per_quad_shared_quad_state",
-                           test_name, count, "runs/s", true);
+    auto reporter = SetUpReporter(story, single_sqs);
+    reporter.AddResult(kMetricStructSerializationTimeUs,
+                       min_time.InMicrosecondsF() / kTimeCheckInterval);
+    reporter.AddResult(kMetricStructSerializationThroughputRunsPerS,
+                       count * 1000 / kTimeLimitMillis);
   }
 
-  static void RunComplexCompositorFrameTest(const std::string& test_name) {
+  static void RunComplexCompositorFrameTest(const std::string& story) {
     CompositorFrame frame;
     frame.metadata.begin_frame_ack = BeginFrameAck(0, 1, true);
 
@@ -283,10 +295,10 @@
     }
 
     render_pass_list.push_back(std::move(pass_in));
-    RunTest(test_name, std::move(frame), UseSingleSharedQuadState::NO);
+    RunTest(story, std::move(frame), UseSingleSharedQuadState::NO);
   }
 
-  static void RunCompositorFrameTest(const std::string& test_name,
+  static void RunCompositorFrameTest(const std::string& story,
                                      uint32_t num_quads,
                                      uint32_t num_passes,
                                      UseSingleSharedQuadState single_sqs) {
@@ -306,14 +318,14 @@
       }
       frame.render_pass_list.push_back(std::move(render_pass));
     }
-    RunTest(test_name, std::move(frame), single_sqs);
+    RunTest(story, std::move(frame), single_sqs);
   }
 
-  static void RunTest(const std::string& test_name,
+  static void RunTest(const std::string& story,
                       CompositorFrame frame,
                       UseSingleSharedQuadState single_sqs) {
-    RunSerializationTestStructTraits(test_name, frame, single_sqs);
-    RunDeserializationTestStructTraits(test_name, frame, single_sqs);
+    RunSerializationTestStructTraits(story, frame, single_sqs);
+    RunDeserializationTestStructTraits(story, frame, single_sqs);
   }
 };
 
diff --git a/storage/browser/blob/blob_builder_from_stream.cc b/storage/browser/blob/blob_builder_from_stream.cc
index 4dd25aa5..6a6758a 100644
--- a/storage/browser/blob/blob_builder_from_stream.cc
+++ b/storage/browser/blob/blob_builder_from_stream.cc
@@ -495,8 +495,7 @@
       items_.back()->item()->length() < kMaxFileSize) {
     auto item = items_.back()->item();
     uint64_t old_file_size = item->length();
-    scoped_refptr<ShareableFileReference> file_reference =
-        static_cast<ShareableFileReference*>(item->data_handle());
+    scoped_refptr<ShareableFileReference> file_reference = item->file_ref_;
     DCHECK(file_reference);
     auto file_size_delta = std::min(kMaxFileSize - old_file_size, length_hint);
     context_->mutable_memory_controller()->GrowFileAllocation(
@@ -618,7 +617,7 @@
   DCHECK(!items_.empty());
   auto item = items_.back()->item();
   DCHECK_EQ(item->type(), BlobDataItem::Type::kFile);
-  DCHECK_EQ(item->data_handle(), file_reference.get());
+  DCHECK_EQ(item->file_ref_, file_reference.get());
 
   item->SetFileModificationTime(modification_time);
   current_total_size_ += bytes_written;
diff --git a/storage/browser/blob/blob_data_builder.cc b/storage/browser/blob/blob_data_builder.cc
index fec479c..bd8caad 100644
--- a/storage/browser/blob/blob_data_builder.cc
+++ b/storage/browser/blob/blob_data_builder.cc
@@ -281,8 +281,7 @@
       case BlobDataItem::Type::kFile: {
         data_item = BlobDataItem::CreateFile(
             source_item->path(), source_item->offset() + item_offset, read_size,
-            source_item->expected_modification_time(),
-            source_item->data_handle_);
+            source_item->expected_modification_time(), source_item->file_ref_);
 
         if (source_item->IsFutureFileItem()) {
           // The source file isn't a real file yet (path is fake), so store the
diff --git a/storage/browser/blob/blob_data_item.cc b/storage/browser/blob/blob_data_item.cc
index 22582a9a..0a98e09 100644
--- a/storage/browser/blob/blob_data_item.cc
+++ b/storage/browser/blob/blob_data_item.cc
@@ -78,12 +78,12 @@
     uint64_t offset,
     uint64_t length,
     base::Time expected_modification_time,
-    scoped_refptr<DataHandle> data_handle) {
+    scoped_refptr<ShareableFileReference> file_ref) {
   auto item =
       base::WrapRefCounted(new BlobDataItem(Type::kFile, offset, length));
   item->path_ = std::move(path);
   item->expected_modification_time_ = std::move(expected_modification_time);
-  item->data_handle_ = std::move(data_handle);
+  item->file_ref_ = std::move(file_ref);
   // TODO(mek): DCHECK(!item->IsFutureFileItem()) when BlobDataBuilder has some
   // other way of slicing a future file.
   return item;
@@ -171,14 +171,15 @@
   bytes_.resize(length_);
 }
 
-void BlobDataItem::PopulateFile(base::FilePath path,
-                                base::Time expected_modification_time,
-                                scoped_refptr<DataHandle> data_handle) {
+void BlobDataItem::PopulateFile(
+    base::FilePath path,
+    base::Time expected_modification_time,
+    scoped_refptr<ShareableFileReference> file_ref) {
   DCHECK_EQ(type_, Type::kFile);
   DCHECK(IsFutureFileItem());
   path_ = std::move(path);
   expected_modification_time_ = std::move(expected_modification_time);
-  data_handle_ = std::move(data_handle);
+  file_ref_ = std::move(file_ref);
 }
 
 void BlobDataItem::ShrinkFile(uint64_t new_length) {
diff --git a/storage/browser/blob/blob_data_item.h b/storage/browser/blob/blob_data_item.h
index bec072f..4b559ed2 100644
--- a/storage/browser/blob/blob_data_item.h
+++ b/storage/browser/blob/blob_data_item.h
@@ -16,6 +16,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "net/base/io_buffer.h"
+#include "storage/browser/blob/shareable_file_reference.h"
 #include "url/gurl.h"
 
 namespace storage {
@@ -102,7 +103,7 @@
       uint64_t offset,
       uint64_t length,
       base::Time expected_modification_time = base::Time(),
-      scoped_refptr<DataHandle> data_handle = nullptr);
+      scoped_refptr<ShareableFileReference> file_ref = nullptr);
   static scoped_refptr<BlobDataItem> CreateFutureFile(uint64_t offset,
                                                       uint64_t length,
                                                       uint64_t file_id);
@@ -148,8 +149,7 @@
   }
 
   DataHandle* data_handle() const {
-    DCHECK(type_ == Type::kFile || type_ == Type::kReadableDataHandle)
-        << static_cast<int>(type_);
+    DCHECK_EQ(type_, Type::kReadableDataHandle) << static_cast<int>(type_);
     return data_handle_.get();
   }
 
@@ -180,7 +180,7 @@
 
   void PopulateFile(base::FilePath path,
                     base::Time expected_modification_time,
-                    scoped_refptr<DataHandle> data_handle);
+                    scoped_refptr<ShareableFileReference> file_ref);
   void ShrinkFile(uint64_t new_length);
   void GrowFile(uint64_t new_length);
   void SetFileModificationTime(base::Time time) {
@@ -198,8 +198,8 @@
   base::Time
       expected_modification_time_;  // For Type::kFile and kFileFilesystem.
 
-  scoped_refptr<DataHandle>
-      data_handle_;  // For Type::kFile and kReadableDataHandle.
+  scoped_refptr<DataHandle> data_handle_;           // For kReadableDataHandle.
+  scoped_refptr<ShareableFileReference> file_ref_;  // For Type::kFile
 
   scoped_refptr<FileSystemContext>
       file_system_context_;  // For Type::kFileFilesystem.
diff --git a/storage/browser/blob/blob_storage_context.cc b/storage/browser/blob/blob_storage_context.cc
index a2bb4c0..ccbbda6 100644
--- a/storage/browser/blob/blob_storage_context.cc
+++ b/storage/browser/blob/blob_storage_context.cc
@@ -520,7 +520,7 @@
               source_item->path(),
               source_item->offset() + copy.source_item_offset, dest_size,
               source_item->expected_modification_time(),
-              source_item->data_handle_);
+              source_item->file_ref_);
           copy.dest_item->set_item(std::move(new_item));
           break;
         }
diff --git a/storage/browser/blob/shareable_file_reference.h b/storage/browser/blob/shareable_file_reference.h
index c009c70..d6f30a8 100644
--- a/storage/browser/blob/shareable_file_reference.h
+++ b/storage/browser/blob/shareable_file_reference.h
@@ -7,7 +7,6 @@
 
 #include "base/component_export.h"
 #include "base/macros.h"
-#include "storage/browser/blob/blob_data_item.h"
 #include "storage/browser/blob/scoped_file.h"
 
 namespace storage {
@@ -17,7 +16,7 @@
 // This class is non-thread-safe and all methods must be called on a single
 // thread.
 class COMPONENT_EXPORT(STORAGE_BROWSER) ShareableFileReference
-    : public BlobDataItem::DataHandle {
+    : public base::RefCounted<ShareableFileReference> {
  public:
   using FinalReleaseCallback = ScopedFile::ScopeOutCallback;
 
@@ -64,8 +63,10 @@
   void AddFinalReleaseCallback(FinalReleaseCallback callback);
 
  private:
+  friend class base::RefCounted<ShareableFileReference>;
+
   ShareableFileReference(ScopedFile scoped_file);
-  ~ShareableFileReference() override;
+  ~ShareableFileReference();
 
   ScopedFile scoped_file_;
 
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index 5adda6e..ac53470 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -2268,23 +2268,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04",
-              "pool": "chrome.tests",
-              "ssd": "0"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index d3cdb8ce..a506976 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -1621,21 +1621,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -3176,22 +3161,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index aa8e68d..5b36587 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -805,21 +805,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -2342,22 +2327,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -3894,22 +3863,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -11573,21 +11526,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -13106,24 +13044,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -14617,21 +14537,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -15994,21 +15899,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -17358,21 +17248,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -18752,21 +18627,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -20147,21 +20007,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -21243,16 +21088,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -22415,19 +22250,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -23339,16 +23161,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -24470,16 +24282,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -25516,16 +25318,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -26562,16 +26354,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -27964,22 +27746,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -29604,22 +29370,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -31244,22 +30994,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -32528,16 +32262,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -33574,16 +33298,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -34620,16 +34334,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -35666,16 +35370,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -36712,16 +36406,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -37953,21 +37637,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -39415,21 +39084,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index f96c1b7..6375cd4 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -1756,16 +1756,6 @@
         "swarming": {
           "can_use_on_swarming_builders": false
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": false
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -3223,22 +3213,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-17134"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -13785,22 +13759,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -15277,21 +15235,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -17068,22 +17011,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -22876,23 +22803,6 @@
           ],
           "expiration": 21600
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15"
-            }
-          ],
-          "expiration": 21600
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 2f94085..6342c7d 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -3094,22 +3094,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -4923,21 +4907,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -6694,21 +6663,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 23176714..28dd68c9 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -832,22 +832,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.10"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -2396,22 +2380,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.11"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -3960,22 +3928,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.12.6"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -5569,22 +5521,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -7168,22 +7104,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 7af9985..6cce8bf 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -4041,24 +4041,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -5618,21 +5600,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -7205,24 +7172,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -9035,25 +8984,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -10821,25 +10751,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -12491,24 +12402,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -13791,19 +13684,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -17873,21 +17753,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 5948508..dffbe54 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -639,16 +639,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -2253,22 +2243,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -4116,22 +4090,6 @@
             }
           ]
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -5710,16 +5668,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
@@ -6964,16 +6912,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "leveldb_service_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "libjingle_xmpp_unittests"
       },
       {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index b957d16..6bd68a0 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1485,10 +1485,6 @@
     "label": "//third_party/leveldatabase:leveldb_put_get_delete_fuzzer",
     "type": "fuzzer",
   },
-  "leveldb_service_unittests": {
-    "label": "//components/services/leveldb:leveldb_service_unittests",
-    "type": "console_test_launcher",
-  },
   "libANGLE": {
     "label": "//third_party/angle:libANGLE",
     "type": "additional_compile_target",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index bdf12ab..f7c29331 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4486,7 +4486,6 @@
           'shards': 3,
         },
       },
-      'leveldb_service_unittests': {},  # https://crbug.com/862709
       'message_center_unittests': {},
       'nacl_loader_unittests': {},
       'native_theme_unittests': {},
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 873d84b..276614b 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1394,10 +1394,9 @@
             ],
             "experiments": [
                 {
-                    "name": "Capacity_512kb_Chunk_64kb",
+                    "name": "Enabled_2MB_v1",
                     "params": {
-                        "capacity_bytes": "524288",
-                        "chunk_bytes": "65536"
+                        "capacity_bytes": "2097152"
                     },
                     "enable_features": [
                         "BlobDataPipeTuning"
@@ -3768,6 +3767,26 @@
             ]
         }
     ],
+    "OffMainThreadServiceWorkerStartup": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "OffMainThreadServiceWorkerStartup"
+                    ]
+                }
+            ]
+        }
+    ],
     "OfferUploadCreditCards": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 6e5d810..aff73cf 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -129,6 +129,10 @@
 #endif
 };
 
+// Enable CSSOM View Scroll Coordinates. https://crbug.com/721759.
+const base::Feature kCSSOMViewScrollCoordinates{
+    "CSSOMViewScrollCoordinates", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables usage of getDisplayMedia() that allows capture of web content, see
 // https://crbug.com/865060.
 const base::Feature kRTCGetDisplayMedia{"RTCGetDisplayMedia",
@@ -294,10 +298,6 @@
 #endif
 };
 
-// Use scroll gestures for scrollbar scrolls (see https://crbug.com/954007).
-const base::Feature kScrollbarInjectScrollGestures{
-    "ScrollbarInjectScrollGestures", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Automatically convert light-themed pages to use a Blink-generated dark theme
 const base::Feature kForceWebContentsDarkMode{
     "WebContentsForceDark", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/common/loader/url_loader_factory_bundle.cc b/third_party/blink/common/loader/url_loader_factory_bundle.cc
index 9052c9116..1476bf6 100644
--- a/third_party/blink/common/loader/url_loader_factory_bundle.cc
+++ b/third_party/blink/common/loader/url_loader_factory_bundle.cc
@@ -39,13 +39,13 @@
     mojo::PendingRemote<network::mojom::URLLoaderFactory>
         pending_default_factory,
     SchemeMap pending_scheme_specific_factories,
-    OriginMap pending_initiator_specific_factories,
+    OriginMap pending_isolated_world_factories,
     bool bypass_redirect_checks)
     : pending_default_factory_(std::move(pending_default_factory)),
       pending_scheme_specific_factories_(
           std::move(pending_scheme_specific_factories)),
-      pending_initiator_specific_factories_(
-          std::move(pending_initiator_specific_factories)),
+      pending_isolated_world_factories_(
+          std::move(pending_isolated_world_factories)),
       bypass_redirect_checks_(bypass_redirect_checks) {}
 
 URLLoaderFactoryBundleInfo::~URLLoaderFactoryBundleInfo() = default;
@@ -57,8 +57,8 @@
   other->pending_appcache_factory_ = std::move(pending_appcache_factory_);
   other->pending_scheme_specific_factories_ =
       std::move(pending_scheme_specific_factories_);
-  other->pending_initiator_specific_factories_ =
-      std::move(pending_initiator_specific_factories_);
+  other->pending_isolated_world_factories_ =
+      std::move(pending_isolated_world_factories_);
   other->bypass_redirect_checks_ = bypass_redirect_checks_;
 
   return base::MakeRefCounted<URLLoaderFactoryBundle>(std::move(other));
@@ -82,9 +82,9 @@
     return it->second.get();
 
   if (request.isolated_world_origin.has_value()) {
-    auto it2 = initiator_specific_factories_.find(
-        request.isolated_world_origin.value());
-    if (it2 != initiator_specific_factories_.end())
+    auto it2 =
+        isolated_world_factories_.find(request.isolated_world_origin.value());
+    if (it2 != isolated_world_factories_.end())
       return it2->second.get();
   }
 
@@ -125,7 +125,7 @@
   auto pending_factories = std::make_unique<blink::URLLoaderFactoryBundleInfo>(
       std::move(pending_default_factory),
       CloneRemoteMapToPendingRemoteMap(scheme_specific_factories_),
-      CloneRemoteMapToPendingRemoteMap(initiator_specific_factories_),
+      CloneRemoteMapToPendingRemoteMap(isolated_world_factories_),
       bypass_redirect_checks_);
 
   if (appcache_factory_) {
@@ -154,8 +154,8 @@
       &scheme_specific_factories_,
       std::move(pending_factories->pending_scheme_specific_factories()));
   BindPendingRemoteMapToRemoteMap(
-      &initiator_specific_factories_,
-      std::move(pending_factories->pending_initiator_specific_factories()));
+      &isolated_world_factories_,
+      std::move(pending_factories->pending_isolated_world_factories()));
   bypass_redirect_checks_ = pending_factories->bypass_redirect_checks();
 }
 
diff --git a/third_party/blink/common/loader/url_loader_factory_bundle_mojom_traits.cc b/third_party/blink/common/loader/url_loader_factory_bundle_mojom_traits.cc
index f63b571..2f037d3c 100644
--- a/third_party/blink/common/loader/url_loader_factory_bundle_mojom_traits.cc
+++ b/third_party/blink/common/loader/url_loader_factory_bundle_mojom_traits.cc
@@ -33,9 +33,9 @@
 }
 
 // static
-blink::URLLoaderFactoryBundleInfo::OriginMap
-Traits::initiator_specific_factories(BundleInfoType& bundle) {
-  return std::move(bundle->pending_initiator_specific_factories());
+blink::URLLoaderFactoryBundleInfo::OriginMap Traits::isolated_world_factories(
+    BundleInfoType& bundle) {
+  return std::move(bundle->pending_isolated_world_factories());
 }
 
 // static
@@ -56,8 +56,8 @@
           &(*out_bundle)->pending_scheme_specific_factories())) {
     return false;
   }
-  if (!data.ReadInitiatorSpecificFactories(
-          &(*out_bundle)->pending_initiator_specific_factories())) {
+  if (!data.ReadIsolatedWorldFactories(
+          &(*out_bundle)->pending_isolated_world_factories())) {
     return false;
   }
 
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index cfd172c..fb1d2d47 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -26,6 +26,7 @@
 BLINK_COMMON_EXPORT extern const base::Feature kFreezePurgeMemoryAllPagesFrozen;
 BLINK_COMMON_EXPORT extern const base::Feature kFreezeUserAgent;
 BLINK_COMMON_EXPORT extern const base::Feature kImplicitRootScroller;
+BLINK_COMMON_EXPORT extern const base::Feature kCSSOMViewScrollCoordinates;
 BLINK_COMMON_EXPORT extern const base::Feature kCSSBackdropFilter;
 BLINK_COMMON_EXPORT extern const base::Feature kDisplayLocking;
 BLINK_COMMON_EXPORT extern const base::Feature kFastBorderRadius;
@@ -81,7 +82,6 @@
     kWebFontsCacheAwareTimeoutAdaption;
 BLINK_COMMON_EXPORT extern const base::Feature
     kBlockingFocusWithoutUserActivation;
-BLINK_COMMON_EXPORT extern const base::Feature kScrollbarInjectScrollGestures;
 
 BLINK_COMMON_EXPORT extern const base::Feature kAudioWorkletRealtimeThread;
 
diff --git a/third_party/blink/public/common/loader/url_loader_factory_bundle.h b/third_party/blink/public/common/loader/url_loader_factory_bundle.h
index c0f1a45..f7d3633 100644
--- a/third_party/blink/public/common/loader/url_loader_factory_bundle.h
+++ b/third_party/blink/public/common/loader/url_loader_factory_bundle.h
@@ -37,9 +37,9 @@
       std::map<std::string,
                mojo::PendingRemote<network::mojom::URLLoaderFactory>>;
 
-  // Map from origin of request initiator to PendingRemote<URLLoaderFactory> for
-  // handling this initiator's requests (e.g., for relaxing CORB for requests
-  // initiated from content scripts).
+  // Map from origin of isolated world to PendingRemote<URLLoaderFactory> for
+  // handling this isolated world's requests (e.g., for relaxing CORB for
+  // requests initiated from content scripts).
   using OriginMap =
       std::map<url::Origin,
                mojo::PendingRemote<network::mojom::URLLoaderFactory>>;
@@ -49,7 +49,7 @@
       mojo::PendingRemote<network::mojom::URLLoaderFactory>
           pending_default_factory,
       SchemeMap scheme_specific_factory_infos,
-      OriginMap initiator_specific_factory_infos,
+      OriginMap isolated_world_factory_infos,
       bool bypass_redirect_checks);
   ~URLLoaderFactoryBundleInfo() override;
 
@@ -66,8 +66,8 @@
   SchemeMap& pending_scheme_specific_factories() {
     return pending_scheme_specific_factories_;
   }
-  OriginMap& pending_initiator_specific_factories() {
-    return pending_initiator_specific_factories_;
+  OriginMap& pending_isolated_world_factories() {
+    return pending_isolated_world_factories_;
   }
 
   bool bypass_redirect_checks() const { return bypass_redirect_checks_; }
@@ -84,7 +84,7 @@
   mojo::PendingRemote<network::mojom::URLLoaderFactory>
       pending_appcache_factory_;
   SchemeMap pending_scheme_specific_factories_;
-  OriginMap pending_initiator_specific_factories_;
+  OriginMap pending_isolated_world_factories_;
   bool bypass_redirect_checks_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryBundleInfo);
@@ -160,12 +160,12 @@
       std::map<std::string, mojo::Remote<network::mojom::URLLoaderFactory>>;
   SchemeMap scheme_specific_factories_;
 
-  // Map from origin of request initiator to Remote<URLLoaderFactory> for
-  // handling this initiator's requests. See also
+  // Map from origin of isolated world to Remote<URLLoaderFactory> for handling
+  // this isolated world's requests. See also
   // URLLoaderFactoryBundleInfo::OriginMap.
   using OriginMap =
       std::map<url::Origin, mojo::Remote<network::mojom::URLLoaderFactory>>;
-  OriginMap initiator_specific_factories_;
+  OriginMap isolated_world_factories_;
 
   bool bypass_redirect_checks_ = false;
 };
diff --git a/third_party/blink/public/common/loader/url_loader_factory_bundle_mojom_traits.h b/third_party/blink/public/common/loader/url_loader_factory_bundle_mojom_traits.h
index 4727643f..cd9c9de 100644
--- a/third_party/blink/public/common/loader/url_loader_factory_bundle_mojom_traits.h
+++ b/third_party/blink/public/common/loader/url_loader_factory_bundle_mojom_traits.h
@@ -33,8 +33,8 @@
   static blink::URLLoaderFactoryBundleInfo::SchemeMap scheme_specific_factories(
       BundleInfoType& bundle);
 
-  static blink::URLLoaderFactoryBundleInfo::OriginMap
-  initiator_specific_factories(BundleInfoType& bundle);
+  static blink::URLLoaderFactoryBundleInfo::OriginMap isolated_world_factories(
+      BundleInfoType& bundle);
 
   static bool bypass_redirect_checks(BundleInfoType& bundle);
 
diff --git a/third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom b/third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom
index b447fe90..024a556 100644
--- a/third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom
+++ b/third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom
@@ -26,12 +26,8 @@
   map<string, network.mojom.URLLoaderFactory> scheme_specific_factories;
 
   // A mapping from isolated world's origin to factory interface.
-  //
-  // TODO(lukasza): https://crbug.com/940068: Rename to
-  // |isolated_world_factories| (here and in other places referring to
-  // "initiator-specific factories).
   map<url.mojom.Origin, network.mojom.URLLoaderFactory>
-      initiator_specific_factories;
+      isolated_world_factories;
 
   // A special factory that is used for AppCache.
   // TODO(https://crbug.com/582750): Drop this when AppCache is deprecated.
diff --git a/third_party/blink/public/mojom/service_worker/embedded_worker.mojom b/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
index 69c71f4..ad82ce9d 100644
--- a/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
+++ b/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
@@ -11,6 +11,7 @@
 import "third_party/blink/public/mojom/devtools/console_message.mojom";
 import "third_party/blink/public/mojom/devtools/devtools_agent.mojom";
 import "third_party/blink/public/mojom/worker/subresource_loader_updater.mojom";
+import "third_party/blink/public/mojom/loader/fetch_client_settings_object.mojom";
 import "third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom";
 import "third_party/blink/public/mojom/renderer_preference_watcher.mojom";
 import "third_party/blink/public/mojom/renderer_preferences.mojom";
@@ -44,6 +45,10 @@
   // https://w3c.github.io/ServiceWorker/#dfn-type
   ScriptType script_type;
 
+  // The outside fetch client settings object. This is used for top-level script
+  // fetch.
+  FetchClientSettingsObject outside_fetch_client_settings_object;
+
   // The string used for "user-agent" HTTP header.
   string user_agent;
 
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 827a217..98c9dcd 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2434,6 +2434,9 @@
   kARIAAnnotationRoles = 3050,
   kIntersectionObserverV2 = 3051,
   kHeavyAdIntervention = 3052,
+  kUserTimingL3 = 3053,
+  kGetGamepadsFromCrossOriginSubframe = 3054,
+  kGetGamepadsFromInsecureContext = 3055,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/web_fetch_client_settings_object.h b/third_party/blink/public/platform/web_fetch_client_settings_object.h
index d2cd4d7f..fbee76a1 100644
--- a/third_party/blink/public/platform/web_fetch_client_settings_object.h
+++ b/third_party/blink/public/platform/web_fetch_client_settings_object.h
@@ -25,6 +25,8 @@
   WebURL outgoing_referrer;
   mojom::InsecureRequestsPolicy insecure_requests_policy;
 
+  WebFetchClientSettingsObject() {}
+
 #if INSIDE_BLINK
   explicit WebFetchClientSettingsObject(
       const FetchClientSettingsObjectSnapshot& snapshot)
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index 1d330d1..66e8a6d 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -111,6 +111,7 @@
   BLINK_PLATFORM_EXPORT static void EnableFormControlsRefresh(bool);
   BLINK_PLATFORM_EXPORT static void EnableGenericSensorExtraClasses(bool);
   BLINK_PLATFORM_EXPORT static void EnableImplicitRootScroller(bool);
+  BLINK_PLATFORM_EXPORT static void EnableCSSOMViewScrollCoordinates(bool);
   BLINK_PLATFORM_EXPORT static void EnableInputMultipleFieldsUI(bool);
   BLINK_PLATFORM_EXPORT static void EnableBuiltInModuleAll(bool);
   BLINK_PLATFORM_EXPORT static void EnableBuiltInModuleInfra(bool);
diff --git a/third_party/blink/public/web/web_embedded_worker_start_data.h b/third_party/blink/public/web/web_embedded_worker_start_data.h
index 6d6952a..abebc1f 100644
--- a/third_party/blink/public/web/web_embedded_worker_start_data.h
+++ b/third_party/blink/public/web/web_embedded_worker_start_data.h
@@ -35,6 +35,7 @@
 #include "services/network/public/mojom/ip_address_space.mojom-shared.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom-shared.h"
 #include "third_party/blink/public/platform/web_content_security_policy.h"
+#include "third_party/blink/public/platform/web_fetch_client_settings_object.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
 
@@ -55,6 +56,8 @@
 
   network::mojom::IPAddressSpace address_space;
 
+  WebFetchClientSettingsObject outside_fetch_client_settings_object;
+
   WebEmbeddedWorkerStartData() : wait_for_debugger_mode(kDontWaitForDebugger) {}
 };
 
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h
index 0999167..bd279e31 100644
--- a/third_party/blink/public/web/web_view.h
+++ b/third_party/blink/public/web/web_view.h
@@ -269,6 +269,9 @@
   // mode (does not have <!doctype html>), the height will stretch to fill the
   // viewport. The returned size has the page zoom factor applied. The lifecycle
   // must be updated to at least layout before calling (see: |UpdateLifecycle|).
+  //
+  // This may only be called when there is a local main frame attached to this
+  // WebView.
   virtual WebSize ContentsPreferredMinimumSize() = 0;
 
   // Requests a page-scale animation based on the specified point/rect.
diff --git a/third_party/blink/renderer/core/DEPS b/third_party/blink/renderer/core/DEPS
index b72fb9b..1629785 100644
--- a/third_party/blink/renderer/core/DEPS
+++ b/third_party/blink/renderer/core/DEPS
@@ -50,6 +50,7 @@
     "+cc/paint/paint_flags.h",
     "+cc/paint/paint_worklet_input.h",
     "+cc/trees/paint_holding_commit_trigger.h",
+    "+components/performance_manager/public/mojom/coordination_unit.mojom-blink.h",
     "+gpu/config/gpu_feature_info.h",
     "-inspector/v8",
     "+inspector/v8/public",
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 54427f7..9587ce8 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -38,6 +38,7 @@
 #include "base/time/time.h"
 #include "cc/input/overscroll_behavior.h"
 #include "cc/input/scroll_snap_data.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom-blink.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/metrics/public/cpp/mojo_ukm_recorder.h"
@@ -45,7 +46,6 @@
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/metrics/public/mojom/ukm_interface.mojom-blink.h"
 #include "services/network/public/mojom/ip_address_space.mojom-blink.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom-blink.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/common/features.h"
@@ -6565,7 +6565,7 @@
 
 namespace {
 
-using resource_coordinator::mojom::InterventionPolicy;
+using performance_manager::mojom::InterventionPolicy;
 
 // A helper function to set the origin trial freeze policy of a document.
 void SetOriginTrialFreezePolicy(
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 8cb8072..c2b3aa06 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1278,8 +1278,16 @@
               kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop);
     }
 
-    return AdjustForAbsoluteZoom::AdjustScroll(
-        scrollable_area->ScrollPosition().X(), *GetLayoutBox());
+    // In order to keep the behavior of element scroll consistent with document
+    // scroll, and consistent with the behavior of other vendors, the scrollLeft
+    // of a box is changed to the offset from |ScrollOrigin()|.
+    if (RuntimeEnabledFeatures::CSSOMViewScrollCoordinatesEnabled()) {
+      return AdjustForAbsoluteZoom::AdjustScroll(
+          scrollable_area->GetScrollOffset().Width(), *GetLayoutBox());
+    } else {
+      return AdjustForAbsoluteZoom::AdjustScroll(
+          scrollable_area->ScrollPosition().X(), *GetLayoutBox());
+    }
   }
 
   return 0;
@@ -1307,8 +1315,16 @@
               kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop);
     }
 
-    return AdjustForAbsoluteZoom::AdjustScroll(
-        scrollable_area->ScrollPosition().Y(), *GetLayoutBox());
+    // In order to keep the behavior of element scroll consistent with document
+    // scroll, and consistent with the behavior of other vendors, the scrollTop
+    // of a box is changed to the offset from |ScrollOrigin()|.
+    if (RuntimeEnabledFeatures::CSSOMViewScrollCoordinatesEnabled()) {
+      return AdjustForAbsoluteZoom::AdjustScroll(
+          scrollable_area->GetScrollOffset().Height(), *GetLayoutBox());
+    } else {
+      return AdjustForAbsoluteZoom::AdjustScroll(
+          scrollable_area->ScrollPosition().Y(), *GetLayoutBox());
+    }
   }
 
   return 0;
@@ -1345,20 +1361,38 @@
       }
     }
 
-    FloatPoint end_point(new_left * box->Style()->EffectiveZoom(),
-                         scrollable_area->ScrollPosition().Y());
-    std::unique_ptr<cc::SnapSelectionStrategy> strategy =
-        cc::SnapSelectionStrategy::CreateForEndPosition(
-            gfx::ScrollOffset(end_point), true, false);
-    end_point = GetDocument()
-                    .GetSnapCoordinator()
-                    .GetSnapPosition(*box, *strategy)
-                    .value_or(end_point);
+    if (RuntimeEnabledFeatures::CSSOMViewScrollCoordinatesEnabled()) {
+      ScrollOffset end_offset(new_left * box->Style()->EffectiveZoom(),
+                              scrollable_area->GetScrollOffset().Height());
+      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+          cc::SnapSelectionStrategy::CreateForEndPosition(
+              gfx::ScrollOffset(
+                  scrollable_area->ScrollOffsetToPosition(end_offset)),
+              true, false);
+      base::Optional<FloatPoint> snap_point =
+          GetDocument().GetSnapCoordinator().GetSnapPosition(*box, *strategy);
+      if (snap_point.has_value()) {
+        end_offset =
+            scrollable_area->ScrollPositionToOffset(snap_point.value());
+      }
+      scrollable_area->SetScrollOffset(end_offset, kProgrammaticScroll,
+                                       kScrollBehaviorAuto);
+    } else {
+      FloatPoint end_point(new_left * box->Style()->EffectiveZoom(),
+                           scrollable_area->ScrollPosition().Y());
+      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+          cc::SnapSelectionStrategy::CreateForEndPosition(
+              gfx::ScrollOffset(end_point), true, false);
+      end_point = GetDocument()
+                      .GetSnapCoordinator()
+                      .GetSnapPosition(*box, *strategy)
+                      .value_or(end_point);
 
-    FloatPoint new_position(end_point.X(),
-                            scrollable_area->ScrollPosition().Y());
-    scrollable_area->ScrollToAbsolutePosition(new_position,
-                                              kScrollBehaviorAuto);
+      FloatPoint new_position(end_point.X(),
+                              scrollable_area->ScrollPosition().Y());
+      scrollable_area->ScrollToAbsolutePosition(new_position,
+                                                kScrollBehaviorAuto);
+    }
   }
 }
 
@@ -1393,19 +1427,38 @@
       }
     }
 
-    FloatPoint end_point(scrollable_area->ScrollPosition().X(),
-                         new_top * box->Style()->EffectiveZoom());
-    std::unique_ptr<cc::SnapSelectionStrategy> strategy =
-        cc::SnapSelectionStrategy::CreateForEndPosition(
-            gfx::ScrollOffset(end_point), false, true);
-    end_point = GetDocument()
-                    .GetSnapCoordinator()
-                    .GetSnapPosition(*box, *strategy)
-                    .value_or(end_point);
-    FloatPoint new_position(scrollable_area->ScrollPosition().X(),
-                            end_point.Y());
-    scrollable_area->ScrollToAbsolutePosition(new_position,
-                                              kScrollBehaviorAuto);
+    if (RuntimeEnabledFeatures::CSSOMViewScrollCoordinatesEnabled()) {
+      ScrollOffset end_offset(scrollable_area->GetScrollOffset().Width(),
+                              new_top * box->Style()->EffectiveZoom());
+      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+          cc::SnapSelectionStrategy::CreateForEndPosition(
+              gfx::ScrollOffset(
+                  scrollable_area->ScrollOffsetToPosition(end_offset)),
+              false, true);
+      base::Optional<FloatPoint> snap_point =
+          GetDocument().GetSnapCoordinator().GetSnapPosition(*box, *strategy);
+      if (snap_point.has_value()) {
+        end_offset =
+            scrollable_area->ScrollPositionToOffset(snap_point.value());
+      }
+
+      scrollable_area->SetScrollOffset(end_offset, kProgrammaticScroll,
+                                       kScrollBehaviorAuto);
+    } else {
+      FloatPoint end_point(scrollable_area->ScrollPosition().X(),
+                           new_top * box->Style()->EffectiveZoom());
+      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+          cc::SnapSelectionStrategy::CreateForEndPosition(
+              gfx::ScrollOffset(end_point), false, true);
+      end_point = GetDocument()
+                      .GetSnapCoordinator()
+                      .GetSnapPosition(*box, *strategy)
+                      .value_or(end_point);
+      FloatPoint new_position(scrollable_area->ScrollPosition().X(),
+                              end_point.Y());
+      scrollable_area->ScrollToAbsolutePosition(new_position,
+                                                kScrollBehaviorAuto);
+    }
   }
 }
 
@@ -1539,54 +1592,86 @@
   if (PaintLayerScrollableArea* scrollable_area = GetScrollableArea()) {
     LayoutBox* box = GetLayoutBox();
     DCHECK(box);
-    FloatPoint new_position(scrollable_area->ScrollPosition().X(),
-                            scrollable_area->ScrollPosition().Y());
-    if (scroll_to_options->hasLeft()) {
-      if (HasLeftwardDirection(*this)) {
+    if (scroll_to_options->hasLeft() && HasLeftwardDirection(*this)) {
+      UseCounter::Count(
+          GetDocument(),
+          WebFeature::
+              kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop);
+      if (scroll_to_options->left() > 0) {
         UseCounter::Count(
             GetDocument(),
             WebFeature::
-                kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop);
-        if (scroll_to_options->left() > 0) {
-          UseCounter::Count(
-              GetDocument(),
-              WebFeature::
-                  kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive);
-        }
+                kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive);
       }
-
-      new_position.SetX(
-          ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options->left()) *
-          box->Style()->EffectiveZoom());
     }
-    if (scroll_to_options->hasTop()) {
-      if (HasUpwardDirection(*this)) {
+    if (scroll_to_options->hasTop() && HasUpwardDirection(*this)) {
+      UseCounter::Count(
+          GetDocument(),
+          WebFeature::
+              kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop);
+      if (scroll_to_options->top() > 0) {
         UseCounter::Count(
             GetDocument(),
             WebFeature::
-                kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop);
-        if (scroll_to_options->top() > 0) {
-          UseCounter::Count(
-              GetDocument(),
-              WebFeature::
-                  kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive);
-        }
+                kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive);
       }
-
-      new_position.SetY(
-          ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options->top()) *
-          box->Style()->EffectiveZoom());
     }
 
-    std::unique_ptr<cc::SnapSelectionStrategy> strategy =
-        cc::SnapSelectionStrategy::CreateForEndPosition(
-            gfx::ScrollOffset(new_position), scroll_to_options->hasLeft(),
-            scroll_to_options->hasTop());
-    new_position = GetDocument()
-                       .GetSnapCoordinator()
-                       .GetSnapPosition(*box, *strategy)
-                       .value_or(new_position);
-    scrollable_area->ScrollToAbsolutePosition(new_position, scroll_behavior);
+    // In order to keep the behavior of element scroll consistent with document
+    // scroll, and consistent with the behavior of other vendors, the
+    // offsets in |scroll_to_options| are treated as the offset from
+    // |ScrollOrigin()|.
+    if (RuntimeEnabledFeatures::CSSOMViewScrollCoordinatesEnabled()) {
+      ScrollOffset new_offset = scrollable_area->GetScrollOffset();
+      if (scroll_to_options->hasLeft()) {
+        new_offset.SetWidth(ScrollableArea::NormalizeNonFiniteScroll(
+                                scroll_to_options->left()) *
+                            box->Style()->EffectiveZoom());
+      }
+      if (scroll_to_options->hasTop()) {
+        new_offset.SetHeight(
+            ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options->top()) *
+            box->Style()->EffectiveZoom());
+      }
+
+      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+          cc::SnapSelectionStrategy::CreateForEndPosition(
+              gfx::ScrollOffset(
+                  scrollable_area->ScrollOffsetToPosition(new_offset)),
+              scroll_to_options->hasLeft(), scroll_to_options->hasTop());
+      base::Optional<FloatPoint> snap_point =
+          GetDocument().GetSnapCoordinator().GetSnapPosition(*box, *strategy);
+      if (snap_point.has_value()) {
+        new_offset =
+            scrollable_area->ScrollPositionToOffset(snap_point.value());
+      }
+
+      scrollable_area->SetScrollOffset(new_offset, kProgrammaticScroll,
+                                       scroll_behavior);
+    } else {
+      FloatPoint new_position(scrollable_area->ScrollPosition().X(),
+                              scrollable_area->ScrollPosition().Y());
+      if (scroll_to_options->hasLeft()) {
+        new_position.SetX(ScrollableArea::NormalizeNonFiniteScroll(
+                              scroll_to_options->left()) *
+                          box->Style()->EffectiveZoom());
+      }
+      if (scroll_to_options->hasTop()) {
+        new_position.SetY(
+            ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options->top()) *
+            box->Style()->EffectiveZoom());
+      }
+
+      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+          cc::SnapSelectionStrategy::CreateForEndPosition(
+              gfx::ScrollOffset(new_position), scroll_to_options->hasLeft(),
+              scroll_to_options->hasTop());
+      new_position = GetDocument()
+                         .GetSnapCoordinator()
+                         .GetSnapPosition(*box, *strategy)
+                         .value_or(new_position);
+      scrollable_area->ScrollToAbsolutePosition(new_position, scroll_behavior);
+    }
   }
 }
 
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 a0d1449c..99413a1 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -2695,9 +2695,9 @@
 }
 
 WebSize WebViewImpl::ContentsPreferredMinimumSize() {
+  DCHECK(AsView().page->MainFrame()->IsLocalFrame());
+
   auto* main_local_frame = DynamicTo<LocalFrame>(AsView().page->MainFrame());
-  if (!main_local_frame)
-    return WebSize();
   Document* document = main_local_frame->GetDocument();
   if (!document || !document->GetLayoutView() || !document->documentElement() ||
       !document->documentElement()->GetLayoutBox())
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 5a6f891..4fb727d 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1641,7 +1641,7 @@
   if (auto* document_resource_coordinator =
           GetDocument()->GetResourceCoordinator()) {
     document_resource_coordinator->SetLifecycleState(
-        resource_coordinator::mojom::LifecycleState::kFrozen);
+        performance_manager::mojom::LifecycleState::kFrozen);
   }
 }
 
@@ -1658,7 +1658,7 @@
   if (auto* document_resource_coordinator =
           GetDocument()->GetResourceCoordinator()) {
     document_resource_coordinator->SetLifecycleState(
-        resource_coordinator::mojom::LifecycleState::kRunning);
+        performance_manager::mojom::LifecycleState::kRunning);
   }
 }
 
diff --git a/third_party/blink/renderer/core/html/forms/resources/color_picker.css b/third_party/blink/renderer/core/html/forms/resources/color_picker.css
index fa7b3a7..dd930e2 100644
--- a/third_party/blink/renderer/core/html/forms/resources/color_picker.css
+++ b/third_party/blink/renderer/core/html/forms/resources/color_picker.css
@@ -197,7 +197,13 @@
     forced-color-adjust: none;
     border-color: WindowText;
   }
+  color-well {
+    border-bottom: 1px solid WindowText;
+  }
   color-selection-ring {
     forced-color-adjust: none;
   }
+  format-toggler {
+    border: 1px solid WindowText;
+  }
 }
\ No newline at end of file
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element.cc b/third_party/blink/renderer/core/html/forms/text_control_element.cc
index f8fc94a..7cbc1b7c 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_element.cc
+++ b/third_party/blink/renderer/core/html/forms/text_control_element.cc
@@ -408,7 +408,8 @@
         index += std::min(length, passed_position.OffsetInContainerNode());
       else
         index += length;
-    } else if (node->HasTagName(kBrTag)) {
+      // Disregard the last auto added placeholder BrTag.
+    } else if (node->HasTagName(kBrTag) && node != inner_editor->lastChild()) {
       ++index;
     }
   }
diff --git a/third_party/blink/renderer/core/input/event_handler_test.cc b/third_party/blink/renderer/core/input/event_handler_test.cc
index 34ac168..7fdb009a 100644
--- a/third_party/blink/renderer/core/input/event_handler_test.cc
+++ b/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -1044,22 +1044,7 @@
   ASSERT_FALSE(chrome_client_->ReceivedRequestForUnbufferedInput());
 }
 
-class EventHandlerScrollbarGestureInjectionTest : public SimTest {
- public:
-  EventHandlerScrollbarGestureInjectionTest() = default;
-
-  void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kScrollbarInjectScrollGestures);
-    SimTest::SetUp();
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(EventHandlerScrollbarGestureInjectionTest,
-       MouseUpOffScrollbarGeneratesScrollEnd) {
+TEST_F(EventHandlerSimTest, MouseUpOffScrollbarGeneratesScrollEnd) {
   WebView().MainFrameWidget()->Resize(WebSize(800, 600));
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1133,7 +1118,7 @@
   }
 }
 
-TEST_F(EventHandlerScrollbarGestureInjectionTest, MouseUpOnlyOnScrollbar) {
+TEST_F(EventHandlerSimTest, MouseUpOnlyOnScrollbar) {
   WebView().MainFrameWidget()->Resize(WebSize(800, 600));
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1185,7 +1170,7 @@
   EXPECT_EQ(WebWidgetClient().GetInjectedScrollGestureData().size(), 0u);
 }
 
-TEST_F(EventHandlerScrollbarGestureInjectionTest, RightClickNoGestures) {
+TEST_F(EventHandlerSimTest, RightClickNoGestures) {
   WebView().MainFrameWidget()->Resize(WebSize(800, 600));
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -1230,8 +1215,7 @@
 #define MAYBE_GestureTapWithScrollSnaps GestureTapWithScrollSnaps
 #endif
 
-TEST_F(EventHandlerScrollbarGestureInjectionTest,
-       MAYBE_GestureTapWithScrollSnaps) {
+TEST_F(EventHandlerSimTest, MAYBE_GestureTapWithScrollSnaps) {
   // Create a page that has scroll snaps enabled for a scroller. Tap on the
   // scrollbar and verify that the SnapController does not immediately cancel
   // the resulting animation during the handling of GestureScrollEnd - this
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index c97dac4..2060248 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -1414,6 +1414,13 @@
 bool LayoutObject::HasDistortingVisualEffects() const {
   // TODO(szager): Check occlusion information propagated from out-of-process
   // parent frame.
+
+  // TODO(szager): Remove CHECK's after diagnosing crash.
+  PaintLayer* enclosing_layer = EnclosingLayer();
+  CHECK(enclosing_layer);
+  CHECK(enclosing_layer->GetLayoutObject()
+            .FirstFragment()
+            .HasLocalBorderBoxProperties());
   PropertyTreeState paint_properties = EnclosingLayer()
                                            ->GetLayoutObject()
                                            .FirstFragment()
@@ -1430,12 +1437,15 @@
     }
   }
 
-  PropertyTreeState root_properties = GetDocument()
-                                          .GetFrame()
-                                          ->LocalFrameRoot()
-                                          .ContentLayoutObject()
-                                          ->FirstFragment()
-                                          .LocalBorderBoxProperties();
+  // TODO(szager): Remove CHECK's after diagnosing crash.
+  CHECK(GetDocument().IsActive());
+  LocalFrame* frame = GetDocument().GetFrame();
+  CHECK(frame);
+  LayoutView* layout_view = frame->LocalFrameRoot().ContentLayoutObject();
+  CHECK(layout_view);
+  CHECK(layout_view->FirstFragment().HasLocalBorderBoxProperties());
+  PropertyTreeState root_properties =
+      layout_view->FirstFragment().LocalBorderBoxProperties();
 
   // The only allowed transforms are 2D translation and proportional up-scaling.
   const auto& translation_2d_or_matrix =
diff --git a/third_party/blink/renderer/core/layout/layout_shift_tracker.cc b/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
index 93f1ea27..d3c7eae 100644
--- a/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
+++ b/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
@@ -28,7 +28,7 @@
 
 static constexpr base::TimeDelta kTimerDelay =
     base::TimeDelta::FromMilliseconds(500);
-static const float kMovementThreshold = 1.0;  // CSS pixels.
+static const float kMovementThreshold = 3.0;  // CSS pixels.
 
 static FloatPoint LogicalStart(const FloatRect& rect,
                                const LayoutObject& object) {
diff --git a/third_party/blink/renderer/core/layout/scrollbars_test.cc b/third_party/blink/renderer/core/layout/scrollbars_test.cc
index 7efc0e2..72ca0a6 100644
--- a/third_party/blink/renderer/core/layout/scrollbars_test.cc
+++ b/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
@@ -163,8 +162,6 @@
   void SetUp() override {
     ScrollbarsTest::SetUp();
     WebView().Scheduler()->EnableVirtualTime();
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kScrollbarInjectScrollGestures);
   }
 
   void TearDown() override {
@@ -195,9 +192,6 @@
         delay);
     test::EnterRunLoop();
   }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_F(ScrollbarsTest, DocumentStyleRecalcPreservesScrollbars) {
diff --git a/third_party/blink/renderer/core/script/pending_script.cc b/third_party/blink/renderer/core/script/pending_script.cc
index 2a353a8..8af9e8f7 100644
--- a/third_party/blink/renderer/core/script/pending_script.cc
+++ b/third_party/blink/renderer/core/script/pending_script.cc
@@ -141,16 +141,9 @@
   }
 
   if (OriginalContextDocument() != context_document) {
-    if (GetScriptType() == mojom::ScriptType::kModule) {
-      // Do not execute module scripts if they are moved between documents.
-      Dispose();
-      return;
-    }
-
-    // TODO(hiroshige): Also do not execute classic scripts.
-    // https://crbug.com/721914
-    UseCounter::Count(context_document,
-                      WebFeature::kEvaluateScriptMovedBetweenDocuments);
+    // Do not execute scripts if they are moved between documents.
+    Dispose();
+    return;
   }
 
   if (OriginalContextDocument() == context_document &&
diff --git a/third_party/blink/renderer/core/scroll/scrollbar.cc b/third_party/blink/renderer/core/scroll/scrollbar.cc
index 2238bcd..7aa526f 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar.cc
@@ -209,14 +209,7 @@
   }
 
   // Handle the arrows and track by injecting a scroll update.
-  if (IsScrollGestureInjectionEnabled()) {
-    InjectScrollGestureForPressedPart(WebInputEvent::kGestureScrollUpdate);
-  } else {
-    scrollable_area_->UserScroll(
-        PressedPartScrollGranularity(),
-        ToScrollDelta(PressedPartScrollDirectionPhysical(), 1),
-        ScrollableArea::ScrollCallback());
-  }
+  InjectScrollGestureForPressedPart(WebInputEvent::kGestureScrollUpdate);
 
   // Always start timer when user press on button since scrollable area maybe
   // infinite scrolling.
@@ -291,12 +284,7 @@
         delta;
     destination_position =
         scrollable_area_->ClampScrollOffset(orientation_, destination_position);
-    if (IsScrollGestureInjectionEnabled()) {
-      InjectGestureScrollUpdateForThumbMove(destination_position);
-    } else {
-      scrollable_area_->SetScrollOffsetSingleAxis(
-          orientation_, destination_position, kUserScroll);
-    }
+    InjectGestureScrollUpdateForThumbMove(destination_position);
     document_drag_pos_ = pos;
     return;
   }
@@ -325,12 +313,8 @@
     float new_offset = static_cast<float>(thumb_pos + delta) *
                            (max_offset - min_offset) / (track_len - thumb_len) +
                        min_offset;
-    if (IsScrollGestureInjectionEnabled()) {
-      InjectGestureScrollUpdateForThumbMove(new_offset);
-    } else {
-      scrollable_area_->SetScrollOffsetSingleAxis(orientation_, new_offset,
-                                                  kUserScroll);
-    }
+
+    InjectGestureScrollUpdateForThumbMove(new_offset);
   }
 }
 
@@ -443,19 +427,13 @@
       scrollable_area_) {
     ScrollOffset delta = ToScrollDelta(PressedPartScrollDirectionPhysical(), 1);
     if (DeltaWillScroll(delta)) {
-      if (IsScrollGestureInjectionEnabled()) {
-        // Taps perform a single scroll begin/update/end sequence of gesture
-        // events. There's no autoscroll timer since long press is not treated
-        // the same as holding a mouse down.
-        InjectScrollGestureForPressedPart(WebInputEvent::kGestureScrollBegin);
-        InjectScrollGestureForPressedPart(WebInputEvent::kGestureScrollUpdate);
-        InjectScrollGestureForPressedPart(WebInputEvent::kGestureScrollEnd);
-      } else {
-        scrollable_area_->UserScroll(
-            PressedPartScrollGranularity(),
-            ToScrollDelta(PressedPartScrollDirectionPhysical(), 1),
-            ScrollableArea::ScrollCallback());
-      }
+      // Taps perform a single scroll begin/update/end sequence of gesture
+      // events. There's no autoscroll timer since long press is not treated
+      // the same as holding a mouse down.
+      InjectScrollGestureForPressedPart(WebInputEvent::kGestureScrollBegin);
+      InjectScrollGestureForPressedPart(WebInputEvent::kGestureScrollUpdate);
+      InjectScrollGestureForPressedPart(WebInputEvent::kGestureScrollEnd);
+
       return true;
     }
   }
@@ -473,12 +451,7 @@
       if (scrollable_area_) {
         float destination_position =
             drag_origin_ + scrollable_area_->MinimumScrollOffset(orientation_);
-        if (IsScrollGestureInjectionEnabled()) {
-          InjectGestureScrollUpdateForThumbMove(destination_position);
-        } else {
-          scrollable_area_->SetScrollOffsetSingleAxis(
-              orientation_, destination_position, kUserScroll);
-        }
+        InjectGestureScrollUpdateForThumbMove(destination_position);
       }
     } else {
       MoveThumb(orientation_ == kHorizontalScrollbar
@@ -545,8 +518,7 @@
       scrollable_area_->MouseExitedScrollbar(*this);
     }
 
-    if (IsScrollGestureInjectionEnabled())
-      InjectScrollGestureForPressedPart(WebInputEvent::kGestureScrollEnd);
+    InjectScrollGestureForPressedPart(WebInputEvent::kGestureScrollEnd);
   }
 }
 
@@ -587,10 +559,6 @@
   AutoscrollPressedPart(GetTheme().InitialAutoscrollTimerDelay());
 }
 
-bool Scrollbar::IsScrollGestureInjectionEnabled() const {
-  return base::FeatureList::IsEnabled(features::kScrollbarInjectScrollGestures);
-}
-
 void Scrollbar::InjectScrollGestureForPressedPart(
     WebInputEvent::Type gesture_type) {
   ScrollOffset delta = ToScrollDelta(PressedPartScrollDirectionPhysical(), 1);
@@ -626,7 +594,6 @@
 void Scrollbar::InjectScrollGesture(WebInputEvent::Type gesture_type,
                                     ScrollOffset delta,
                                     ScrollGranularity granularity) {
-  DCHECK(IsScrollGestureInjectionEnabled());
   DCHECK(scrollable_area_);
 
   if (gesture_type == WebInputEvent::Type::kGestureScrollEnd &&
diff --git a/third_party/blink/renderer/core/scroll/scrollbar.h b/third_party/blink/renderer/core/scroll/scrollbar.h
index f2d773c..811322d 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar.h
+++ b/third_party/blink/renderer/core/scroll/scrollbar.h
@@ -212,7 +212,6 @@
   void StopTimerIfNeeded();
   void AutoscrollPressedPart(base::TimeDelta delay);
   bool HandleTapGesture();
-  bool IsScrollGestureInjectionEnabled() const;
   void InjectScrollGestureForPressedPart(WebInputEvent::Type gesture_type);
   void InjectGestureScrollUpdateForThumbMove(float single_axis_target_offset);
   void InjectScrollGesture(WebInputEvent::Type type,
diff --git a/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc b/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
index a4d2d3f..2c14dfd 100644
--- a/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
+++ b/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
@@ -70,7 +70,7 @@
   for (const auto& animation : sandwich_) {
     DCHECK(animation->HasValidTarget());
 
-    if (!animation->CurrentIntervalIsActive(elapsed))
+    if (!animation->NeedsIntervalUpdate(elapsed))
       continue;
     animation->UpdateInterval(elapsed);
   }
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
index 24842f7..d009512 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -188,7 +188,7 @@
       is_scheduled_(false),
       interval_{SMILTime::Unresolved(), SMILTime::Unresolved()},
       previous_interval_{SMILTime::Unresolved(), SMILTime::Unresolved()},
-      next_interval_time_(SMILTime::Unresolved()),
+      next_interval_time_(SMILTime::Earliest()),
       active_state_(kInactive),
       restart_(kRestartAlways),
       fill_(kFillRemove),
@@ -257,9 +257,8 @@
   is_waiting_for_first_interval_ = true;
   interval_ = {SMILTime::Unresolved(), SMILTime::Unresolved()};
   previous_interval_ = {SMILTime::Unresolved(), SMILTime::Unresolved()};
-  next_interval_time_ = SMILTime::Unresolved();
+  next_interval_time_ = SMILTime::Earliest();
   last_progress_ = {0.0f, 0};
-  ResolveFirstInterval(SMILTime());
 }
 
 Node::InsertionNotificationRequest SVGSMILElement::InsertedInto(
@@ -819,15 +818,6 @@
   return SMILInterval(SMILTime::Unresolved(), SMILTime::Unresolved());
 }
 
-bool SVGSMILElement::ResolveFirstInterval(SMILTime presentation_time) {
-  SMILInterval first_interval =
-      ResolveInterval(SMILTime::Earliest(), presentation_time);
-  if (!first_interval.IsResolved() || first_interval == interval_)
-    return false;
-  SetNewInterval(first_interval, presentation_time);
-  return true;
-}
-
 void SVGSMILElement::SetNewInterval(const SMILInterval& interval,
                                     SMILTime presentation_time) {
   interval_ = interval;
@@ -873,14 +863,8 @@
   SMILTime current_presentation_time =
       time_container_ ? time_container_->CurrentDocumentTime() : SMILTime();
   DCHECK(!current_presentation_time.IsUnresolved());
-  if (is_waiting_for_first_interval_) {
-    instance_lists_have_changed_ = false;
-    ResolveFirstInterval(current_presentation_time);
-    return;
-  }
-  SMILInterval old_interval = interval_;
   UpdateInterval(current_presentation_time);
-  if (interval_ != old_interval) {
+  if (interval_has_changed_) {
     if (GetActiveState() == kActive &&
         interval_.BeginsAfter(current_presentation_time)) {
       active_state_ = DetermineActiveState(current_presentation_time);
@@ -914,7 +898,7 @@
 
 bool SVGSMILElement::HandleIntervalRestart(SMILTime presentation_time) {
   Restart restart = GetRestart();
-  if (restart == kRestartNever)
+  if (!is_waiting_for_first_interval_ && restart == kRestartNever)
     return false;
   if (!interval_.IsResolved() || interval_.EndsBefore(presentation_time))
     return true;
@@ -929,7 +913,6 @@
 }
 
 void SVGSMILElement::UpdateInterval(SMILTime presentation_time) {
-  DCHECK(!is_waiting_for_first_interval_);
   if (instance_lists_have_changed_) {
     instance_lists_have_changed_ = false;
     DiscardOrRevalidateCurrentInterval(presentation_time);
@@ -937,7 +920,9 @@
   if (!HandleIntervalRestart(presentation_time))
     return;
   SMILTime begin_after =
-      interval_.IsResolved() ? interval_.end : SMILTime::Earliest();
+      !is_waiting_for_first_interval_ && interval_.IsResolved()
+          ? interval_.end
+          : SMILTime::Earliest();
   SMILInterval next_interval = ResolveInterval(begin_after, presentation_time);
   if (!next_interval.IsResolved() || next_interval == interval_)
     return;
@@ -950,8 +935,7 @@
 void SVGSMILElement::AddedToTimeContainer() {
   DCHECK(time_container_);
   SMILTime current_presentation_time = time_container_->CurrentDocumentTime();
-  if (is_waiting_for_first_interval_)
-    ResolveFirstInterval(current_presentation_time);
+  UpdateInterval(current_presentation_time);
 
   if (IntervalBegin() <= current_presentation_time ||
       NextProgressTime(current_presentation_time).IsFinite()) {
@@ -1069,36 +1053,12 @@
          GetActiveState() == kFrozen;
 }
 
-bool SVGSMILElement::CurrentIntervalIsActive(SMILTime elapsed) {
+bool SVGSMILElement::NeedsIntervalUpdate(SMILTime elapsed) const {
   // Check we're connected to something and that our conditions have been
   // "connected".
   DCHECK(time_container_);
   DCHECK(conditions_connected_);
-  // If |is_waiting_for_first_interval_| is true, |interval_| can either be the
-  // actual interval that has been resolved, or unresolved if there are no
-  // begin times yet.
-  DCHECK(is_waiting_for_first_interval_ || interval_.IsResolved());
-
-  // No interval has been resolved yet, we're waiting for an event of some
-  // sort.
-  if (!interval_.IsResolved()) {
-    DCHECK_EQ(GetActiveState(), kInactive);
-    return false;
-  }
-
-  // We have a current interval, but it has not started yet.
-  if (interval_.BeginsAfter(elapsed)) {
-    DCHECK_NE(GetActiveState(), kActive);
-    return false;
-  }
-
-  if (is_waiting_for_first_interval_) {
-    // The current internal must be the first, and has started, so clear the flag and (re)resolve.
-    is_waiting_for_first_interval_ = false;
-    if (ResolveFirstInterval(elapsed))
-      time_container_->MarkIntervalsDirty();
-  }
-  return true;
+  return elapsed >= next_interval_time_;
 }
 
 void SVGSMILElement::UpdateActiveState(SMILTime elapsed) {
@@ -1247,6 +1207,10 @@
   AddInstanceTimeAndUpdate(kBegin, Elapsed(), SMILTimeOrigin::kLinkActivation);
 }
 
+void SVGSMILElement::StartedActiveInterval() {
+  is_waiting_for_first_interval_ = false;
+}
+
 void SVGSMILElement::EndedActiveInterval() {
   RemoveInstanceTimesWithOrigin(begin_times_, SMILTimeOrigin::kScript);
   RemoveInstanceTimesWithOrigin(end_times_, SMILTimeOrigin::kScript);
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
index dcfff72..0031ab0 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
@@ -84,7 +84,7 @@
   SMILTime IntervalBegin() const { return interval_.begin; }
   SMILTime SimpleDuration() const;
 
-  bool CurrentIntervalIsActive(SMILTime elapsed);
+  bool NeedsIntervalUpdate(SMILTime elapsed) const;
   void UpdateInterval(SMILTime presentation_time);
   void UpdateActiveState(SMILTime elapsed);
   void UpdateProgressState(SMILTime presentation_time);
@@ -141,6 +141,8 @@
   virtual void WillChangeAnimationTarget();
   virtual void DidChangeAnimationTarget();
 
+  virtual void StartedActiveInterval();
+
   QualifiedName attribute_name_;
 
  private:
@@ -148,7 +150,6 @@
   void ClearResourceAndEventBaseReferences();
   void ClearConditions();
 
-  virtual void StartedActiveInterval() = 0;
   void EndedActiveInterval();
   virtual void UpdateAnimation(float percent,
                                unsigned repeat,
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.cc b/third_party/blink/renderer/core/svg/svg_animation_element.cc
index 430dada..0040d0a 100644
--- a/third_party/blink/renderer/core/svg/svg_animation_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animation_element.cc
@@ -529,6 +529,8 @@
 }
 
 void SVGAnimationElement::StartedActiveInterval() {
+  SVGSMILElement::StartedActiveInterval();
+
   animation_valid_ = false;
 
   if (!IsValid() || !HasValidTarget())
diff --git a/third_party/blink/renderer/core/svg/svg_discard_element.h b/third_party/blink/renderer/core/svg/svg_discard_element.h
index ade098b..dffcf52 100644
--- a/third_party/blink/renderer/core/svg/svg_discard_element.h
+++ b/third_party/blink/renderer/core/svg/svg_discard_element.h
@@ -51,7 +51,6 @@
 
   bool OverwritesUnderlyingAnimationValue() const override { return false; }
 
-  void StartedActiveInterval() override {}
   void UpdateAnimation(float percent,
                        unsigned repeat,
                        SVGSMILElement* result_element) override {}
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 33af28cb..5a7917ae 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -1798,9 +1798,9 @@
   const cc::TouchActionRegion& touch_action_region =
       graphics_layer->CcLayer()->touch_action_region();
   if (!touch_action_region.GetAllRegions().IsEmpty()) {
-    const auto& layer_position = graphics_layer->CcLayer()->position();
+    const auto& layer_position = graphics_layer->GetOffsetFromTransformNode();
     const auto& layer_bounds = graphics_layer->CcLayer()->bounds();
-    IntRect layer_rect(layer_position.x(), layer_position.y(),
+    IntRect layer_rect(layer_position.X(), layer_position.Y(),
                        layer_bounds.width(), layer_bounds.height());
 
     Vector<IntRect> layer_hit_test_rects;
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc
index 83c0564..aad39caf 100644
--- a/third_party/blink/renderer/core/timing/performance.cc
+++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -644,14 +644,12 @@
 
 PerformanceMark* Performance::mark(ScriptState* script_state,
                                    const AtomicString& mark_name,
-                                   ExceptionState& exception_state) {
-  return mark(script_state, mark_name, nullptr, exception_state);
-}
-
-PerformanceMark* Performance::mark(ScriptState* script_state,
-                                   const AtomicString& mark_name,
                                    PerformanceMarkOptions* mark_options,
                                    ExceptionState& exception_state) {
+  if (mark_options &&
+      (mark_options->hasStartTime() || mark_options->hasDetail())) {
+    UseCounter::Count(GetExecutionContext(), WebFeature::kUserTimingL3);
+  }
   PerformanceMark* performance_mark = GetUserTiming().CreatePerformanceMark(
       script_state, mark_name, mark_options, exception_state);
   if (performance_mark) {
@@ -723,6 +721,7 @@
   if (start_or_options.IsPerformanceMeasureOptions() &&
       !IsMeasureOptionsEmpty(
           *start_or_options.GetAsPerformanceMeasureOptions())) {
+    UseCounter::Count(GetExecutionContext(), WebFeature::kUserTimingL3);
     // measure("name", { start, end }, *)
     if (end_mark) {
       exception_state.ThrowTypeError(
diff --git a/third_party/blink/renderer/core/timing/performance.h b/third_party/blink/renderer/core/timing/performance.h
index 0cd0245..3edacae3 100644
--- a/third_party/blink/renderer/core/timing/performance.h
+++ b/third_party/blink/renderer/core/timing/performance.h
@@ -188,10 +188,6 @@
 
   PerformanceMark* mark(ScriptState*,
                         const AtomicString& mark_name,
-                        ExceptionState&);
-
-  PerformanceMark* mark(ScriptState*,
-                        const AtomicString& mark_name,
                         PerformanceMarkOptions* mark_options,
                         ExceptionState&);
 
diff --git a/third_party/blink/renderer/core/timing/window_performance_test.cc b/third_party/blink/renderer/core/timing/window_performance_test.cc
index 8fe7b956..5e7bf3f5 100644
--- a/third_party/blink/renderer/core/timing/window_performance_test.cc
+++ b/third_party/blink/renderer/core/timing/window_performance_test.cc
@@ -205,12 +205,12 @@
   DummyExceptionStateForTesting exception_state;
   test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(2));
   for (int i = 0; i < 8; i++) {
-    performance_->mark(scope.GetScriptState(), AtomicString::Number(i),
+    performance_->mark(scope.GetScriptState(), AtomicString::Number(i), nullptr,
                        exception_state);
   }
   test_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(2));
   for (int i = 8; i < 17; i++) {
-    performance_->mark(scope.GetScriptState(), AtomicString::Number(i),
+    performance_->mark(scope.GetScriptState(), AtomicString::Number(i), nullptr,
                        exception_state);
   }
   PerformanceEntryVector entries = performance_->getEntries();
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
index 8f2775e..ab71b22 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
@@ -44,7 +44,6 @@
 #include "third_party/blink/renderer/core/messaging/post_message_options.h"
 #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/core/workers/dedicated_worker_object_proxy.h"
 #include "third_party/blink/renderer/core/workers/dedicated_worker_thread.h"
 #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
@@ -209,8 +208,6 @@
   // "worker" otherwise."
   mojom::RequestContextType destination = mojom::RequestContextType::WORKER;
 
-  Modulator* modulator = Modulator::From(ScriptController()->GetScriptState());
-
   // Step 13: "... Fetch a module worker script graph given url, outside
   // settings, destination, the value of the credentials member of options, and
   // inside settings."
@@ -218,7 +215,8 @@
                     outside_resource_timing_notifier, destination,
                     credentials_mode,
                     ModuleScriptCustomFetchType::kWorkerConstructor,
-                    MakeGarbageCollected<WorkerModuleTreeClient>(modulator));
+                    MakeGarbageCollected<WorkerModuleTreeClient>(
+                        ScriptController()->GetScriptState()));
 }
 
 const String DedicatedWorkerGlobalScope::name() const {
diff --git a/third_party/blink/renderer/core/workers/worker_module_tree_client.cc b/third_party/blink/renderer/core/workers/worker_module_tree_client.cc
index 7bd745d..8c75b65 100644
--- a/third_party/blink/renderer/core/workers/worker_module_tree_client.cc
+++ b/third_party/blink/renderer/core/workers/worker_module_tree_client.cc
@@ -12,17 +12,16 @@
 
 namespace blink {
 
-WorkerModuleTreeClient::WorkerModuleTreeClient(Modulator* modulator)
-    : modulator_(modulator) {}
+WorkerModuleTreeClient::WorkerModuleTreeClient(ScriptState* script_state)
+    : script_state_(script_state) {}
 
 // A partial implementation of the "Processing model" algorithm in the HTML
 // WebWorker spec:
 // https://html.spec.whatwg.org/C/#worker-processing-model
 void WorkerModuleTreeClient::NotifyModuleTreeLoadFinished(
     ModuleScript* module_script) {
-  auto* execution_context =
-      ExecutionContext::From(modulator_->GetScriptState());
-  auto* worker_global_scope = To<WorkerGlobalScope>(execution_context);
+  auto* worker_global_scope =
+      To<WorkerGlobalScope>(ExecutionContext::From(script_state_));
   blink::WorkerReportingProxy& worker_reporting_proxy =
       worker_global_scope->ReportingProxy();
 
@@ -52,7 +51,7 @@
 }
 
 void WorkerModuleTreeClient::Trace(blink::Visitor* visitor) {
-  visitor->Trace(modulator_);
+  visitor->Trace(script_state_);
   ModuleTreeClient::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/core/workers/worker_module_tree_client.h b/third_party/blink/renderer/core/workers/worker_module_tree_client.h
index f8fb0894..e965595 100644
--- a/third_party/blink/renderer/core/workers/worker_module_tree_client.h
+++ b/third_party/blink/renderer/core/workers/worker_module_tree_client.h
@@ -12,11 +12,12 @@
 namespace blink {
 
 class ModuleScript;
+class ScriptState;
 
 // A ModuleTreeClient that lives on the worker context's thread.
 class CORE_EXPORT WorkerModuleTreeClient final : public ModuleTreeClient {
  public:
-  explicit WorkerModuleTreeClient(Modulator*);
+  explicit WorkerModuleTreeClient(ScriptState*);
 
   // Implements ModuleTreeClient.
   void NotifyModuleTreeLoadFinished(ModuleScript*) final;
@@ -24,7 +25,7 @@
   void Trace(blink::Visitor*) override;
 
  private:
-  Member<Modulator> modulator_;
+  Member<ScriptState> script_state_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/devtools/front_end/Tests.js b/third_party/blink/renderer/devtools/front_end/Tests.js
index 1b3f736..c9e7139 100644
--- a/third_party/blink/renderer/devtools/front_end/Tests.js
+++ b/third_party/blink/renderer/devtools/front_end/Tests.js
@@ -1437,6 +1437,7 @@
         baseURL + 'echoheader?Cookie', undefined, 200, ['cache-control'], 'devtools-test-cookie=same-site-cookie');
     await testCase('data:text/html,<body>hello</body>', undefined, 200, [], '<body>hello</body>');
     await testCase(fileURL, undefined, 200, [], '<html>\n<body>\nDummy page.\n</body>\n</html>\n');
+    await testCase(fileURL + 'thisfileshouldnotbefound', undefined, 404, [], '');
 
     this.releaseControl();
   };
diff --git a/third_party/blink/renderer/devtools/front_end/elements/ComputedStyleWidget.js b/third_party/blink/renderer/devtools/front_end/elements/ComputedStyleWidget.js
index 1a8cf0d..726d5ad 100644
--- a/third_party/blink/renderer/devtools/front_end/elements/ComputedStyleWidget.js
+++ b/third_party/blink/renderer/devtools/front_end/elements/ComputedStyleWidget.js
@@ -224,6 +224,8 @@
         treeElement.listItemElement.addEventListener('mousedown', e => e.consume(), false);
         treeElement.listItemElement.addEventListener('dblclick', e => e.consume(), false);
         treeElement.listItemElement.addEventListener('click', handleClick.bind(null, treeElement), false);
+        treeElement.listItemElement.addEventListener(
+            'contextmenu', this._handleContextMenuEvent.bind(this, matchedStyles, activeProperty));
         const gotoSourceElement = UI.Icon.create('mediumicon-arrow-in-circle', 'goto-source-icon');
         gotoSourceElement.addEventListener('click', this._navigateToSource.bind(this, activeProperty));
         propertyValueElement.appendChild(gotoSourceElement);
@@ -319,6 +321,9 @@
 
       const traceTreeElement = new UI.TreeElement();
       traceTreeElement.title = trace;
+
+      traceTreeElement.listItemElement.addEventListener(
+          'contextmenu', this._handleContextMenuEvent.bind(this, matchedStyles, property));
       rootTreeElement.appendChild(traceTreeElement);
     }
     return /** @type {!SDK.CSSProperty} */ (activeProperty);
@@ -326,6 +331,28 @@
 
   /**
    * @param {!SDK.CSSMatchedStyles} matchedStyles
+   * @param {!SDK.CSSProperty} property
+   * @param {!Event} event
+   */
+  _handleContextMenuEvent(matchedStyles, property, event) {
+    const contextMenu = new UI.ContextMenu(event);
+    const rule = property.ownerStyle.parentRule;
+
+    if (rule) {
+      const header = rule.styleSheetId ? matchedStyles.cssModel().styleSheetHeaderForId(rule.styleSheetId) : null;
+      if (header && !header.isAnonymousInlineStyleSheet()) {
+        contextMenu.defaultSection().appendItem(ls`Navigate to selector source`, () => {
+          Elements.StylePropertiesSection.tryNavigateToRuleLocation(matchedStyles, rule);
+        });
+      }
+    }
+
+    contextMenu.defaultSection().appendItem(ls`Navigate to style`, () => Common.Revealer.reveal(property));
+    contextMenu.show();
+  }
+
+  /**
+   * @param {!SDK.CSSMatchedStyles} matchedStyles
    * @return {!Map<string, !Array<!SDK.CSSProperty>>}
    */
   _computePropertyTraces(matchedStyles) {
diff --git a/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js b/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
index 7743ed1..1d2a3b6 100644
--- a/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
+++ b/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
@@ -979,12 +979,7 @@
       return createTextNode('');
     }
 
-    let ruleLocation;
-    if (rule instanceof SDK.CSSStyleRule) {
-      ruleLocation = rule.style.range;
-    } else if (rule instanceof SDK.CSSKeyframeRule) {
-      ruleLocation = rule.key().range;
-    }
+    const ruleLocation = this._getRuleLocationFromCSSRule(rule);
 
     const header = rule.styleSheetId ? matchedStyles.cssModel().styleSheetHeaderForId(rule.styleSheetId) : null;
     if (ruleLocation && rule.styleSheetId && header && !header.isAnonymousInlineStyleSheet()) {
@@ -1012,6 +1007,39 @@
   }
 
   /**
+   * @param {!SDK.CSSRule} rule
+   * @return {?TextUtils.TextRange}
+   */
+  static _getRuleLocationFromCSSRule(rule) {
+    let ruleLocation = null;
+    if (rule instanceof SDK.CSSStyleRule) {
+      ruleLocation = rule.style.range;
+    } else if (rule instanceof SDK.CSSKeyframeRule) {
+      ruleLocation = rule.key().range;
+    }
+    return ruleLocation;
+  }
+
+  /**
+   * @param {!SDK.CSSMatchedStyles} matchedStyles
+   * @param {?SDK.CSSRule} rule
+   */
+  static tryNavigateToRuleLocation(matchedStyles, rule) {
+    if (!rule) {
+      return;
+    }
+
+    const ruleLocation = this._getRuleLocationFromCSSRule(rule);
+    const header = rule.styleSheetId ? matchedStyles.cssModel().styleSheetHeaderForId(rule.styleSheetId) : null;
+
+    if (ruleLocation && rule.styleSheetId && header && !header.isAnonymousInlineStyleSheet()) {
+      const matchingSelectorLocation =
+          this._getCSSSelectorLocation(matchedStyles.cssModel(), rule.styleSheetId, ruleLocation);
+      this._revealSelectorSource(matchingSelectorLocation, true);
+    }
+  }
+
+  /**
    * @param {!SDK.CSSModel} cssModel
    * @param {!Components.Linkifier} linkifier
    * @param {string} styleSheetId
@@ -1019,11 +1047,21 @@
    * @return {!Node}
    */
   static _linkifyRuleLocation(cssModel, linkifier, styleSheetId, ruleLocation) {
+    const matchingSelectorLocation = this._getCSSSelectorLocation(cssModel, styleSheetId, ruleLocation);
+    return linkifier.linkifyCSSLocation(matchingSelectorLocation);
+  }
+
+  /**
+   * @param {!SDK.CSSModel} cssModel
+   * @param {string} styleSheetId
+   * @param {!TextUtils.TextRange} ruleLocation
+   * @return {!SDK.CSSLocation}
+   */
+  static _getCSSSelectorLocation(cssModel, styleSheetId, ruleLocation) {
     const styleSheetHeader = cssModel.styleSheetHeaderForId(styleSheetId);
     const lineNumber = styleSheetHeader.lineNumberInSource(ruleLocation.startLine);
     const columnNumber = styleSheetHeader.columnNumberInSource(ruleLocation.startLine, ruleLocation.startColumn);
-    const matchingSelectorLocation = new SDK.CSSLocation(styleSheetHeader, lineNumber, columnNumber);
-    return linkifier.linkifyCSSLocation(matchingSelectorLocation);
+    return new SDK.CSSLocation(styleSheetHeader, lineNumber, columnNumber);
   }
 
   /**
@@ -1828,6 +1866,14 @@
       return;
     }
     const rawLocation = new SDK.CSSLocation(header, rule.lineNumberInSource(index), rule.columnNumberInSource(index));
+    Elements.StylePropertiesSection._revealSelectorSource(rawLocation, focus);
+  }
+
+  /**
+   * @param {!SDK.CSSLocation} rawLocation
+   * @param {boolean} focus
+   */
+  static _revealSelectorSource(rawLocation, focus) {
     const uiLocation = Bindings.cssWorkspaceBinding.rawLocationToUILocation(rawLocation);
     if (uiLocation) {
       Common.Revealer.reveal(uiLocation, !focus);
diff --git a/third_party/blink/renderer/devtools/front_end/elements/elements_strings.grdp b/third_party/blink/renderer/devtools/front_end/elements/elements_strings.grdp
index 7ea3753..a09dba6 100644
--- a/third_party/blink/renderer/devtools/front_end/elements/elements_strings.grdp
+++ b/third_party/blink/renderer/devtools/front_end/elements/elements_strings.grdp
@@ -42,6 +42,9 @@
   <message name="IDS_DEVTOOLS_26396cca3eae28fc6e39123edb2f1510" desc="Context menu item for style property in edit mode">
     Reveal in Sources panel
   </message>
+  <message name="IDS_DEVTOOLS_2864a2d95e17e3032a3a6e69a51d0256" desc="Context menu item in Elements panel to navigate to style in styles pane">
+    Navigate to style
+  </message>
   <message name="IDS_DEVTOOLS_28c0a3050f784583d52339ddb0bc1274" desc="Text in Elements Tree Element of the Elements panel">
     Paste element
   </message>
@@ -183,6 +186,9 @@
   <message name="IDS_DEVTOOLS_91d17eff6a1529e8a4f67a5aa4cabec7" desc="No matches element text content in Computed Style Widget of the Elements panel">
     No matching property
   </message>
+  <message name="IDS_DEVTOOLS_924843c5b24bc69ed7da2bff699de4f1" desc="Context menu item in Elements panel to navigate to css selector source">
+    Navigate to selector source
+  </message>
   <message name="IDS_DEVTOOLS_97d28fbc573f9f331f5b1886b5c1eeef" desc="Text in Elements Tree Element of the Elements panel">
     Copy full XPath
   </message>
diff --git a/third_party/blink/renderer/devtools/front_end/protocol/InspectorBackend.js b/third_party/blink/renderer/devtools/front_end/protocol/InspectorBackend.js
index 3bdb696..943fc161 100644
--- a/third_party/blink/renderer/devtools/front_end/protocol/InspectorBackend.js
+++ b/third_party/blink/renderer/devtools/front_end/protocol/InspectorBackend.js
@@ -413,10 +413,41 @@
 
     const messageObject = /** @type {!Object} */ ((typeof message === 'string') ? JSON.parse(message) : message);
 
+    // Send all messages to proxy connections.
+    let proxyConnectionIsActive = false;
+    for (const session of this._sessions.values()) {
+      if (!session.proxyConnection) {
+        continue;
+      }
+
+      // Only the Audits panel has use proxy connections. If it is ever possible to have multiple active at the
+      // same time, it should be test thoroughly.
+      if (proxyConnectionIsActive) {
+        Protocol.InspectorBackend.reportProtocolError(
+            'Protocol Error: multiple proxy connections are not explicitly supported right now', messageObject);
+      }
+
+      if (session.proxyConnection._onMessage) {
+        session.proxyConnection._onMessage(messageObject);
+        proxyConnectionIsActive = true;
+      } else {
+        Protocol.InspectorBackend.reportProtocolError(
+            'Protocol Error: the session has a proxyConnection with no _onMessage', messageObject);
+      }
+    }
+
     const sessionId = messageObject.sessionId || '';
     const session = this._sessions.get(sessionId);
     if (!session) {
-      Protocol.InspectorBackend.reportProtocolError('Protocol Error: the message with wrong session id', messageObject);
+      if (!proxyConnectionIsActive) {
+        Protocol.InspectorBackend.reportProtocolError(
+            'Protocol Error: the message with wrong session id', messageObject);
+      }
+      return;
+    }
+
+    // If this message is directly for the target controlled by the proxy connection, don't handle it.
+    if (session.proxyConnection) {
       return;
     }
 
@@ -424,21 +455,13 @@
       Protocol.NodeURL.patch(messageObject);
     }
 
-    if (session.proxyConnection) {
-      if (session.proxyConnection._onMessage) {
-        session.proxyConnection._onMessage(messageObject);
-      } else {
-        Protocol.InspectorBackend.reportProtocolError(
-            'Protocol Error: the message has a proxyConnection with no _onMessage', messageObject);
-      }
-      return;
-    }
-
     if ('id' in messageObject) {  // just a response for some request
       const callback = session.callbacks.get(messageObject.id);
       session.callbacks.delete(messageObject.id);
       if (!callback) {
-        Protocol.InspectorBackend.reportProtocolError('Protocol Error: the message with wrong id', messageObject);
+        if (!proxyConnectionIsActive) {
+          Protocol.InspectorBackend.reportProtocolError('Protocol Error: the message with wrong id', messageObject);
+        }
         return;
       }
 
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/ChildTargetManager.js b/third_party/blink/renderer/devtools/front_end/sdk/ChildTargetManager.js
index 5eb79b0..e5c75ee8 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/ChildTargetManager.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/ChildTargetManager.js
@@ -216,8 +216,8 @@
     const sessionId = /** @type {string} */ (await targetAgent.attachToTarget(targetId, true /* flatten */));
     const connection = new SDK.ParallelConnection(targetRouter.connection(), sessionId);
     targetRouter.registerSession(target, sessionId, connection);
-    connection.setOnDisconnect(async () => {
-      await targetAgent.detachFromTarget(sessionId);
+    connection.setOnDisconnect(() => {
+      targetAgent.detachFromTarget(sessionId);
       targetRouter.unregisterSession(sessionId);
     });
     return {connection, sessionId};
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/Connections.js b/third_party/blink/renderer/devtools/front_end/sdk/Connections.js
index 9da0513..ebc59487 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/Connections.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/Connections.js
@@ -294,7 +294,10 @@
    */
   sendRawMessage(message) {
     const messageObject = JSON.parse(message);
-    messageObject.sessionId = this._sessionId;
+    // If the message isn't for a specific session, it must be for the root session.
+    if (!messageObject.sessionId) {
+      messageObject.sessionId = this._sessionId;
+    }
     this._connection.sendRawMessage(JSON.stringify(messageObject));
   }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index b7a829c..5d7d9fc 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -121,6 +121,7 @@
     AddPermissionStatusListener();
   documents_.insert(&document);
   document.View()->RegisterForLifecycleNotifications(this);
+  relation_cache_->Init();
 }
 
 AXObjectCacheImpl::~AXObjectCacheImpl() {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_test.cc b/third_party/blink/renderer/modules/accessibility/ax_object_test.cc
index 2bf649a..b5426a0 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_test.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_test.cc
@@ -396,5 +396,55 @@
   ASSERT_EQ(ax_select->FirstChild()->ChildCount(), 1);
 }
 
+TEST_F(AccessibilityTest, InitRelationCache) {
+  // All of the other tests already have accessibility initialized
+  // first, but we don't want to in this test.
+  //
+  // Get rid of the AXContext so the AXObjectCache is destroyed.
+  ax_context_.reset(nullptr);
+
+  SetBodyInnerHTML(R"HTML(
+      <ul id="ul" aria-owns="li"></ul>
+      <label for="a"></label>
+      <input id="a">
+      <input id="b">
+      <div role="section" id="div">
+        <li id="li"></li>
+      </div>
+    )HTML");
+
+  // Now recreate an AXContext, simulating what happens if accessibility
+  // is enabled after the document is loaded.
+  ax_context_.reset(new AXContext(GetDocument()));
+
+  const AXObject* root = GetAXRootObject();
+  ASSERT_NE(nullptr, root);
+  const AXObject* input_a = GetAXObjectByElementId("a");
+  ASSERT_NE(nullptr, input_a);
+  const AXObject* input_b = GetAXObjectByElementId("b");
+  ASSERT_NE(nullptr, input_b);
+
+  EXPECT_TRUE(
+      GetAXObjectCache().MayHaveHTMLLabel(ToHTMLElement(*input_a->GetNode())));
+  EXPECT_FALSE(
+      GetAXObjectCache().MayHaveHTMLLabel(ToHTMLElement(*input_b->GetNode())));
+
+  // Note: retrieve the LI first and check that its parent is not
+  // the paragraph element. If we were to retrieve the UL element,
+  // that would trigger the aria-owns check and wouln't allow us to
+  // test whether the relation cache was initialized.
+  const AXObject* li = GetAXObjectByElementId("li");
+  ASSERT_NE(nullptr, li);
+
+  const AXObject* div = GetAXObjectByElementId("div");
+  ASSERT_NE(nullptr, div);
+  EXPECT_NE(li->ParentObjectUnignored(), div);
+
+  const AXObject* ul = GetAXObjectByElementId("ul");
+  ASSERT_NE(nullptr, ul);
+
+  EXPECT_EQ(li->ParentObjectUnignored(), ul);
+}
+
 }  // namespace test
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
index 02eae00..3c53dd8 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/accessibility/ax_relation_cache.h"
 
 #include "base/memory/ptr_util.h"
+#include "third_party/blink/renderer/core/dom/element_traversal.h"
 #include "third_party/blink/renderer/core/html/forms/html_label_element.h"
 
 namespace blink {
@@ -16,6 +17,24 @@
 
 AXRelationCache::~AXRelationCache() = default;
 
+void AXRelationCache::Init() {
+  // Init the relation cache with elements already in the document.
+  Document& document = object_cache_->GetDocument();
+  for (Element& element :
+       ElementTraversal::DescendantsOf(*document.documentElement())) {
+    const auto& id = element.FastGetAttribute(kForAttr);
+    if (!id.IsEmpty())
+      all_previously_seen_label_target_ids_.insert(id);
+
+    if (element.FastHasAttribute(kAriaOwnsAttr)) {
+      if (AXObject* obj = object_cache_->GetOrCreate(&element)) {
+        obj->ClearChildren();
+        obj->AddChildren();
+      }
+    }
+  }
+}
+
 bool AXRelationCache::IsAriaOwned(const AXObject* child) const {
   return aria_owned_child_to_owner_mapping_.Contains(child->AXObjectID());
 }
@@ -271,6 +290,7 @@
 
 void AXRelationCache::LabelChanged(Node* node) {
   const auto& id = To<HTMLElement>(node)->FastGetAttribute(kForAttr);
+  LOG(ERROR) << "LabelChanged " << id;
   if (!id.IsEmpty()) {
     all_previously_seen_label_target_ids_.insert(id);
     if (auto* control = To<HTMLLabelElement>(node)->control())
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
index a96097f..2dec5cfb 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
@@ -22,6 +22,9 @@
   explicit AXRelationCache(AXObjectCacheImpl*);
   virtual ~AXRelationCache();
 
+  // Scan the initial document.
+  void Init();
+
   // Returns true if the given object's position in the tree was due to
   // aria-owns.
   bool IsAriaOwned(const AXObject*) const;
diff --git a/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h b/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h
index 7461c5b..0608c4e 100644
--- a/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h
+++ b/third_party/blink/renderer/modules/accessibility/testing/accessibility_test.h
@@ -44,12 +44,13 @@
 
   std::string PrintAXTree() const;
 
+ protected:
+  std::unique_ptr<AXContext> ax_context_;
+
  private:
   std::ostringstream& PrintAXTreeHelper(std::ostringstream&,
                                         const AXObject* root,
                                         size_t level) const;
-
-  std::unique_ptr<AXContext> ax_context_;
 };
 
 }  // namespace test
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
index 1d8e4d8b..e293b99 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
@@ -262,7 +262,8 @@
   std::unique_ptr<CrossThreadFetchClientSettingsObjectData>
       fetch_client_setting_object_data = CreateFetchClientSettingsObjectData(
           worker_start_data->script_url, starter_origin.get(),
-          starter_https_state, worker_start_data->address_space);
+          starter_https_state, worker_start_data->address_space,
+          worker_start_data->outside_fetch_client_settings_object);
 
   // > Switching on job's worker type, run these substeps with the following
   // > options:
@@ -302,24 +303,30 @@
     const KURL& script_url,
     const SecurityOrigin* security_origin,
     const HttpsState& https_state,
-    network::mojom::IPAddressSpace address_space) {
-  // TODO(crbug.com/967265): Currently we create an incomplete outside settings
-  // object from |worker_start_data| but we should create a proper outside
-  // settings objects depending on the situation. For new worker case, this
-  // should be the Document that called navigator.serviceWorker.register(). For
-  // ServiceWorkerRegistration#update() case, it should be the Document that
-  // called update(). For soft update case, it seems to be 'null' document.
-  //
-  // To get a correct settings, we need to make a way to pass the settings
-  // object over mojo IPCs.
+    network::mojom::IPAddressSpace address_space,
+    const WebFetchClientSettingsObject& passed_settings_object) {
+  // TODO(crbug.com/967265): Currently |passed_settings_object| doesn't contain
+  // enough parameters to create a complete outside settings object. Pass
+  // all necessary information from the parent execution context.
+  // For new worker case, the parent is the Document that called
+  // navigator.serviceWorker.register(). For ServiceWorkerRegistration#update()
+  // case, it should be the Document that called update(). For soft update case,
+  // it seems to be 'null' document.
+
+  WebInsecureRequestPolicy insecure_requests_policy =
+      passed_settings_object.insecure_requests_policy ==
+              mojom::InsecureRequestsPolicy::kUpgrade
+          ? kUpgradeInsecureRequests
+          : kBlockAllMixedContent;
 
   return std::make_unique<CrossThreadFetchClientSettingsObjectData>(
       script_url.Copy() /* global_object_url */,
       script_url.Copy() /* base_url */, security_origin->IsolatedCopy(),
-      network::mojom::ReferrerPolicy::kDefault,
-      script_url.GetString().IsolatedCopy() /* outgoing_referrer */,
+      passed_settings_object.referrer_policy,
+      KURL::CreateIsolated(
+          passed_settings_object.outgoing_referrer.GetString()),
       https_state, AllowedByNosniff::MimeTypeCheck::kLax, address_space,
-      kBlockAllMixedContent /* insecure_requests_policy */,
+      insecure_requests_policy,
       FetchClientSettingsObject::InsecureNavigationsSet(),
       false /* mixed_autoupgrade_opt_out */);
 }
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
index b6bec07..42ca0d0 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
@@ -92,10 +92,12 @@
   // Creates a cross-thread copyable outside settings object for top-level
   // worker script fetch.
   std::unique_ptr<CrossThreadFetchClientSettingsObjectData>
-  CreateFetchClientSettingsObjectData(const KURL& script_url,
-                                      const SecurityOrigin*,
-                                      const HttpsState&,
-                                      network::mojom::IPAddressSpace);
+  CreateFetchClientSettingsObjectData(
+      const KURL& script_url,
+      const SecurityOrigin*,
+      const HttpsState&,
+      network::mojom::IPAddressSpace,
+      const WebFetchClientSettingsObject& passed_settings_object);
 
   // Client must remain valid through the entire life time of the worker.
   WebServiceWorkerContextClient* const worker_context_client_;
diff --git a/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc b/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
index ea4946e..b59b275 100644
--- a/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
+++ b/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
@@ -114,6 +114,17 @@
   }
   is_gamepads_exposed_ = true;
 
+  ExecutionContext* context =
+      DomWindow() ? DomWindow()->GetExecutionContext() : nullptr;
+
+  if (GetFrame() && GetFrame()->IsCrossOriginSubframe()) {
+    UseCounter::Count(context, WebFeature::kGetGamepadsFromCrossOriginSubframe);
+  }
+
+  if (context && !context->IsSecureContext()) {
+    UseCounter::Count(context, WebFeature::kGetGamepadsFromInsecureContext);
+  }
+
   return gamepads_.Get();
 }
 
diff --git a/third_party/blink/renderer/modules/payments/payment_handler_utils.cc b/third_party/blink/renderer/modules/payments/payment_handler_utils.cc
index 96f625bc..57ce848 100644
--- a/third_party/blink/renderer/modules/payments/payment_handler_utils.cc
+++ b/third_party/blink/renderer/modules/payments/payment_handler_utils.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/payments/payment_handler_utils.h"
 
+#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-blink.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 
diff --git a/third_party/blink/renderer/modules/payments/payment_handler_utils.h b/third_party/blink/renderer/modules/payments/payment_handler_utils.h
index 63a4fae..d1d824f 100644
--- a/third_party/blink/renderer/modules/payments/payment_handler_utils.h
+++ b/third_party/blink/renderer/modules/payments/payment_handler_utils.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_HANDLER_UTILS_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_HANDLER_UTILS_H_
 
-#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-blink.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-blink-forward.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
diff --git a/third_party/blink/renderer/modules/payments/payment_request.h b/third_party/blink/renderer/modules/payments/payment_request.h
index 62101861..2315ff6 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.h
+++ b/third_party/blink/renderer/modules/payments/payment_request.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
-#include "components/payments/mojom/payment_request_data.mojom-blink.h"
+#include "components/payments/mojom/payment_request_data.mojom-blink-forward.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/payments/payment_request.mojom-blink.h"
diff --git a/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.h b/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.h
index 0b54fc2..a9428dc 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.h
+++ b/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_REQUEST_RESPOND_WITH_OBSERVER_H_
 
 #include "third_party/blink/public/mojom/payments/payment_app.mojom-blink.h"
-#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-blink.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-blink-forward.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/modules/service_worker/respond_with_observer.h"
 
diff --git a/third_party/blink/renderer/modules/payments/payment_response.h b/third_party/blink/renderer/modules/payments/payment_response.h
index 05af654d..c890b37 100644
--- a/third_party/blink/renderer/modules/payments/payment_response.h
+++ b/third_party/blink/renderer/modules/payments/payment_response.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_RESPONSE_H_
 
 #include "base/macros.h"
-#include "third_party/blink/public/mojom/payments/payment_request.mojom-blink.h"
+#include "third_party/blink/public/mojom/payments/payment_request.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc
index eec9ff8..ca3088c 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc
@@ -174,7 +174,23 @@
 
   quic::QuicRstStreamFrame rst_frame(quic::kInvalidControlFrameId, kStreamId,
                                      quic::QUIC_STREAM_CANCELLED, 0);
+  if (!VersionHasIetfQuicFrames(connection_->version().transport_version)) {
+    // Google RST_STREAM closes the stream in both directions. A RST_STREAM
+    // is then sent to the peer to communicate the final byte offset.
+    EXPECT_CALL(session_,
+                SendRstStream(kStreamId, quic::QUIC_RST_ACKNOWLEDGEMENT, 0));
+  }
   stream_->OnStreamReset(rst_frame);
+  if (VersionHasIetfQuicFrames(connection_->version().transport_version)) {
+    // In IETF QUIC, the RST_STREAM only closes the stream in one direction.
+    // A STOP_SENDING frame in require to induce the a RST_STREAM being
+    // send to close the other direction.
+    EXPECT_CALL(*connection_, SendControlFrame(_));
+    EXPECT_CALL(*connection_, OnStreamReset(kStreamId, testing::_));
+    quic::QuicStopSendingFrame stop_sending_frame(quic::kInvalidControlFrameId,
+                                                  kStreamId, 0);
+    session_.OnStopSendingFrame(stop_sending_frame);
+  }
 
   EXPECT_TRUE(stream_->IsClosedForTesting());
 }
diff --git a/third_party/blink/renderer/modules/presentation/mock_presentation_service.h b/third_party/blink/renderer/modules/presentation/mock_presentation_service.h
index cc570dac..236a2c2 100644
--- a/third_party/blink/renderer/modules/presentation/mock_presentation_service.h
+++ b/third_party/blink/renderer/modules/presentation/mock_presentation_service.h
@@ -7,7 +7,7 @@
 
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink.h"
+#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink-forward.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/presentation/presentation_availability_observer.h b/third_party/blink/renderer/modules/presentation/presentation_availability_observer.h
index efd4203..5ac1e43 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_availability_observer.h
+++ b/third_party/blink/renderer/modules/presentation/presentation_availability_observer.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PRESENTATION_PRESENTATION_AVAILABILITY_OBSERVER_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_PRESENTATION_PRESENTATION_AVAILABILITY_OBSERVER_H_
 
-#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink.h"
+#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink-forward.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
diff --git a/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h b/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h
index ef6bb42e..0dac738 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h
+++ b/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks.h
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
-#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink.h"
+#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink-forward.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
diff --git a/third_party/blink/renderer/modules/presentation/presentation_error.cc b/third_party/blink/renderer/modules/presentation/presentation_error.cc
index 7f9db69..72083a5 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_error.cc
+++ b/third_party/blink/renderer/modules/presentation/presentation_error.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/presentation/presentation_error.h"
 
+#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/presentation/presentation_error.h b/third_party/blink/renderer/modules/presentation/presentation_error.h
index 46cb65f..62f5fcbd 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_error.h
+++ b/third_party/blink/renderer/modules/presentation/presentation_error.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PRESENTATION_PRESENTATION_ERROR_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_PRESENTATION_PRESENTATION_ERROR_H_
 
-#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink.h"
+#include "third_party/blink/public/mojom/presentation/presentation.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/push_messaging/push_error.cc b/third_party/blink/renderer/modules/push_messaging/push_error.cc
index c2edc0d0..1ae288c 100644
--- a/third_party/blink/renderer/modules/push_messaging/push_error.cc
+++ b/third_party/blink/renderer/modules/push_messaging/push_error.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/push_messaging/push_error.h"
 
+#include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-blink.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
diff --git a/third_party/blink/renderer/modules/push_messaging/push_error.h b/third_party/blink/renderer/modules/push_messaging/push_error.h
index 045878d..b48a8f4 100644
--- a/third_party/blink/renderer/modules/push_messaging/push_error.h
+++ b/third_party/blink/renderer/modules/push_messaging/push_error.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PUSH_MESSAGING_PUSH_ERROR_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_PUSH_MESSAGING_PUSH_ERROR_H_
 
-#include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-blink.h"
+#include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
diff --git a/third_party/blink/renderer/modules/push_messaging/push_messaging_client.cc b/third_party/blink/renderer/modules/push_messaging/push_messaging_client.cc
index ecd69c6..692dfc4 100644
--- a/third_party/blink/renderer/modules/push_messaging/push_messaging_client.cc
+++ b/third_party/blink/renderer/modules/push_messaging/push_messaging_client.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/mojom/manifest/manifest.mojom-blink.h"
 #include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/web/web_local_frame.h"
diff --git a/third_party/blink/renderer/modules/push_messaging/push_messaging_client.h b/third_party/blink/renderer/modules/push_messaging/push_messaging_client.h
index a147866f..dab40d0 100644
--- a/third_party/blink/renderer/modules/push_messaging/push_messaging_client.h
+++ b/third_party/blink/renderer/modules/push_messaging/push_messaging_client.h
@@ -10,7 +10,7 @@
 
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "third_party/blink/public/mojom/manifest/manifest.mojom-blink.h"
+#include "third_party/blink/public/mojom/manifest/manifest.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-blink.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/modules/push_messaging/push_subscription_callbacks.h"
diff --git a/third_party/blink/renderer/modules/push_messaging/push_provider.h b/third_party/blink/renderer/modules/push_messaging/push_provider.h
index 79e69841..4ac49e8 100644
--- a/third_party/blink/renderer/modules/push_messaging/push_provider.h
+++ b/third_party/blink/renderer/modules/push_messaging/push_provider.h
@@ -13,7 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-blink.h"
-#include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom-blink.h"
+#include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom-blink-forward.h"
 #include "third_party/blink/renderer/modules/push_messaging/push_subscription_callbacks.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
diff --git a/third_party/blink/renderer/modules/push_messaging/push_subscription.h b/third_party/blink/renderer/modules/push_messaging/push_subscription.h
index 3c99499..8098e52 100644
--- a/third_party/blink/renderer/modules/push_messaging/push_subscription.h
+++ b/third_party/blink/renderer/modules/push_messaging/push_subscription.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-blink.h"
+#include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/core/dom/dom_time_stamp.h"
diff --git a/third_party/blink/renderer/modules/screen_orientation/DEPS b/third_party/blink/renderer/modules/screen_orientation/DEPS
index 46ea48e..a8e4bf80 100644
--- a/third_party/blink/renderer/modules/screen_orientation/DEPS
+++ b/third_party/blink/renderer/modules/screen_orientation/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
     "+mojo/public/cpp/bindings/associated_interface_ptr.h",
     "+services/device/public/mojom/screen_orientation.mojom-blink.h",
+    "+services/device/public/mojom/screen_orientation.mojom-blink-forward.h",
     "-third_party/blink/renderer/modules",
     "+third_party/blink/renderer/modules/event_target_modules.h",
     "+third_party/blink/renderer/modules/modules_export.h",
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index 78bdbdc2..c50950453 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -300,7 +300,7 @@
                     mojom::RequestContextType::SERVICE_WORKER, credentials_mode,
                     ModuleScriptCustomFetchType::kWorkerConstructor,
                     MakeGarbageCollected<ServiceWorkerModuleTreeClient>(
-                        Modulator::From(ScriptController()->GetScriptState())));
+                        ScriptController()->GetScriptState()));
 }
 
 void ServiceWorkerGlobalScope::Dispose() {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc b/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc
index 04d76da..6136ce3 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.cc
@@ -12,8 +12,8 @@
 namespace blink {
 
 ServiceWorkerModuleTreeClient::ServiceWorkerModuleTreeClient(
-    Modulator* modulator)
-    : modulator_(modulator) {}
+    ScriptState* script_state)
+    : script_state_(script_state) {}
 
 // This client is used for both new and installed scripts. In the new scripts
 // case, this is a partial implementation of the custom "perform the fetch" hook
@@ -23,9 +23,8 @@
 // script resource.
 void ServiceWorkerModuleTreeClient::NotifyModuleTreeLoadFinished(
     ModuleScript* module_script) {
-  auto* execution_context =
-      ExecutionContext::From(modulator_->GetScriptState());
-  auto* worker_global_scope = To<WorkerGlobalScope>(execution_context);
+  auto* worker_global_scope =
+      To<WorkerGlobalScope>(ExecutionContext::From(script_state_));
   blink::WorkerReportingProxy& worker_reporting_proxy =
       worker_global_scope->ReportingProxy();
 
@@ -48,7 +47,7 @@
 }
 
 void ServiceWorkerModuleTreeClient::Trace(blink::Visitor* visitor) {
-  visitor->Trace(modulator_);
+  visitor->Trace(script_state_);
   ModuleTreeClient::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.h b/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.h
index e6cae49..94e2ec6 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.h
@@ -12,12 +12,13 @@
 namespace blink {
 
 class ModuleScript;
+class ScriptState;
 
 // This is an implementation of ModuleTreeClient for service workers that lives
 // on the worker context's thread.
 class ServiceWorkerModuleTreeClient final : public ModuleTreeClient {
  public:
-  explicit ServiceWorkerModuleTreeClient(Modulator*);
+  explicit ServiceWorkerModuleTreeClient(ScriptState*);
 
   // Implements ModuleTreeClient.
   void NotifyModuleTreeLoadFinished(ModuleScript*) final;
@@ -25,7 +26,7 @@
   void Trace(blink::Visitor*) override;
 
  private:
-  Member<Modulator> modulator_;
+  Member<ScriptState> script_state_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc
index 82dcc844..23713f10 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context.cc
@@ -146,7 +146,7 @@
   RegisterExtension<WebGLMultiDrawInstanced>(webgl_multi_draw_instanced_,
                                              kDraftExtension);
   RegisterExtension<WebGLVideoTexture>(webgl_video_texture_, kDraftExtension);
-  RegisterExtension<OVRMultiview2>(ovr_multiview2_, kDraftExtension);
+  RegisterExtension<OVRMultiview2>(ovr_multiview2_);
 }
 
 void WebGL2RenderingContext::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc
index 97cfbc7..5cb9dbb4 100644
--- a/third_party/blink/renderer/modules/xr/xr.cc
+++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -530,6 +530,15 @@
   }
 }
 
+void XR::SetFramesThrottled(const XRSession* session, bool throttled) {
+  // The service only cares if the immersive session is throttling frames.
+  if (session->immersive()) {
+    // If we have an immersive session, we should have a service.
+    DCHECK(service_);
+    service_->SetFramesThrottled(throttled);
+  }
+}
+
 ScriptPromise XR::supportsSession(ScriptState* script_state,
                                   const String& mode,
                                   ExceptionState& exception_state) {
diff --git a/third_party/blink/renderer/modules/xr/xr.h b/third_party/blink/renderer/modules/xr/xr.h
index aa1e0137..9d97333 100644
--- a/third_party/blink/renderer/modules/xr/xr.h
+++ b/third_party/blink/renderer/modules/xr/xr.h
@@ -92,6 +92,8 @@
 
   void ExitPresent();
 
+  void SetFramesThrottled(const XRSession* session, bool throttled);
+
   base::TimeTicks NavigationStart() const { return navigation_start_; }
 
  private:
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc
index c61b7b89..2691f2d6 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -909,13 +909,39 @@
     }
   }
 
-  // We can request a frame if we're not hidden, we don't already have a pending
-  // frame, we have pending callbacks, and we will have a base layer when it
-  // resolves.
-  bool can_request_frame =
-      visibility_state_ != XRVisibilityState::HIDDEN && !pending_frame_ &&
-      !callback_collection_->IsEmpty() && will_have_base_layer;
-  if (can_request_frame) {
+  // A page will not be allowed to get frames if its visibility state is hidden.
+  bool page_allowed_frames = visibility_state_ != XRVisibilityState::HIDDEN;
+
+  // A page is configured properly if it will have a base layer when the frame
+  // callback gets resolved.
+  bool page_configured_properly = will_have_base_layer;
+
+  // If we have an outstanding callback registered, then we know that the page
+  // actually wants frames.
+  bool page_wants_frame = !callback_collection_->IsEmpty();
+
+  // A page can process frames if it has its appropriate base layer set and has
+  // indicated that it actually wants frames.
+  bool page_can_process_frames = page_configured_properly && page_wants_frame;
+
+  // We consider frames to be throttled if the page is not allowed frames, but
+  // otherwise would be able to receive them. Therefore, if the page isn't in a
+  // state to process frames, it doesn't matter if we are throttling it, any
+  // "stalls" should be attributed to the page being poorly behaved.
+  bool frames_throttled = page_can_process_frames && !page_allowed_frames;
+
+  // If our throttled state has changed, notify anyone who may care
+  if (frames_throttled_ != frames_throttled) {
+    frames_throttled_ = frames_throttled;
+    xr_->SetFramesThrottled(this, frames_throttled_);
+  }
+
+  // We can request a frame if we don't have one already pending, the page is
+  // allowed to request frames, and the page is set up to properly handle frames
+  // and wants one.
+  bool request_frame =
+      !pending_frame_ && page_allowed_frames && page_can_process_frames;
+  if (request_frame) {
     xr_->frameProvider()->RequestFrame(this);
     pending_frame_ = true;
   }
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h
index ed6bd2e0..f3af97c 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.h
+++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -341,6 +341,7 @@
   bool resolving_frame_ = false;
   bool update_views_next_frame_ = false;
   bool views_dirty_ = true;
+  bool frames_throttled_ = false;
 
   // Indicates that we've already logged a metric, so don't need to log it
   // again.
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index 9a64c19..b1d8403 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -224,6 +224,10 @@
   RuntimeEnabledFeatures::SetImplicitRootScrollerEnabled(enable);
 }
 
+void WebRuntimeFeatures::EnableCSSOMViewScrollCoordinates(bool enable) {
+  RuntimeEnabledFeatures::SetCSSOMViewScrollCoordinatesEnabled(enable);
+}
+
 void WebRuntimeFeatures::EnableInputMultipleFieldsUI(bool enable) {
   RuntimeEnabledFeatures::SetInputMultipleFieldsUIEnabled(enable);
 }
diff --git a/third_party/blink/renderer/platform/graphics/decoding_image_generator.cc b/third_party/blink/renderer/platform/graphics/decoding_image_generator.cc
index ddde5f68..40567fe 100644
--- a/third_party/blink/renderer/platform/graphics/decoding_image_generator.cc
+++ b/third_party/blink/renderer/platform/graphics/decoding_image_generator.cc
@@ -25,8 +25,8 @@
 
 #include "third_party/blink/renderer/platform/graphics/decoding_image_generator.h"
 
-#include <utility>
 #include <memory>
+#include <utility>
 
 #include "third_party/blink/renderer/platform/graphics/image_frame_generator.h"
 #include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
@@ -39,27 +39,6 @@
 
 namespace blink {
 
-namespace {
-
-// These filename extension strings come from ImageDecoder::FilenameExtension.
-PaintImage::ImageType FileExtensionToImageType(String image_extension) {
-  if (image_extension == "png")
-    return PaintImage::ImageType::kPNG;
-  if (image_extension == "jpg")
-    return PaintImage::ImageType::kJPEG;
-  if (image_extension == "webp")
-    return PaintImage::ImageType::kWEBP;
-  if (image_extension == "gif")
-    return PaintImage::ImageType::kGIF;
-  if (image_extension == "ico")
-    return PaintImage::ImageType::kICO;
-  if (image_extension == "bmp")
-    return PaintImage::ImageType::kBMP;
-  return PaintImage::ImageType::kInvalid;
-}
-
-}  // namespace
-
 // static
 std::unique_ptr<SkImageGenerator>
 DecodingImageGenerator::CreateAsSkImageGenerator(sk_sp<SkData> data) {
@@ -88,11 +67,13 @@
 
   WebVector<FrameMetadata> frames;
   frames.emplace_back(FrameMetadata());
+  cc::ImageHeaderMetadata image_metadata =
+      decoder->MakeMetadataForDecodeAcceleration();
+  image_metadata.all_data_received_prior_to_decode = true;
   sk_sp<DecodingImageGenerator> generator = DecodingImageGenerator::Create(
       std::move(frame), info, std::move(segment_reader), std::move(frames),
       PaintImage::GetNextContentId(), true /* all_data_received */,
-      true /* is_eligible_for_accelerated_decoding */,
-      false /* can_yuv_decode */, decoder->FilenameExtension());
+      false /* can_yuv_decode */, image_metadata);
   return std::make_unique<SkiaPaintImageGenerator>(
       std::move(generator), PaintImage::kDefaultFrameIndex,
       PaintImage::kDefaultGeneratorClientId);
@@ -106,14 +87,11 @@
     WebVector<FrameMetadata> frames,
     PaintImage::ContentId content_id,
     bool all_data_received,
-    bool is_eligible_for_accelerated_decoding,
     bool can_yuv_decode,
-    String image_type) {
-  PaintImage::ImageType paint_image_type = FileExtensionToImageType(image_type);
+    const cc::ImageHeaderMetadata& image_metadata) {
   return sk_sp<DecodingImageGenerator>(new DecodingImageGenerator(
       std::move(frame_generator), info, std::move(data), std::move(frames),
-      content_id, all_data_received, is_eligible_for_accelerated_decoding,
-      can_yuv_decode, paint_image_type));
+      content_id, all_data_received, can_yuv_decode, image_metadata));
 }
 
 DecodingImageGenerator::DecodingImageGenerator(
@@ -123,25 +101,18 @@
     WebVector<FrameMetadata> frames,
     PaintImage::ContentId complete_frame_content_id,
     bool all_data_received,
-    bool is_eligible_for_accelerated_decoding,
     bool can_yuv_decode,
-    PaintImage::ImageType image_type)
+    const cc::ImageHeaderMetadata& image_metadata)
     : PaintImageGenerator(info, frames.ReleaseVector()),
       frame_generator_(std::move(frame_generator)),
       data_(std::move(data)),
       all_data_received_(all_data_received),
-      is_eligible_for_accelerated_decoding_(
-          is_eligible_for_accelerated_decoding),
       can_yuv_decode_(can_yuv_decode),
       complete_frame_content_id_(complete_frame_content_id),
-      image_type_(image_type) {}
+      image_metadata_(image_metadata) {}
 
 DecodingImageGenerator::~DecodingImageGenerator() = default;
 
-bool DecodingImageGenerator::IsEligibleForAcceleratedDecoding() const {
-  return is_eligible_for_accelerated_decoding_;
-}
-
 sk_sp<SkData> DecodingImageGenerator::GetEncodedData() const {
   TRACE_EVENT0("blink", "DecodingImageGenerator::refEncodedData");
 
@@ -317,4 +288,9 @@
   return PaintImageGenerator::GetContentIdForFrame(frame_index);
 }
 
+const cc::ImageHeaderMetadata*
+DecodingImageGenerator::GetMetadataForDecodeAcceleration() const {
+  return &image_metadata_;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/decoding_image_generator.h b/third_party/blink/renderer/platform/graphics/decoding_image_generator.h
index aeb18534..b72f3bd 100644
--- a/third_party/blink/renderer/platform/graphics/decoding_image_generator.h
+++ b/third_party/blink/renderer/platform/graphics/decoding_image_generator.h
@@ -63,14 +63,12 @@
       WebVector<FrameMetadata>,
       PaintImage::ContentId,
       bool all_data_received,
-      bool is_eligible_for_accelerated_decoding,
       bool can_yuv_decode,
-      String image_type);
+      const cc::ImageHeaderMetadata& image_metadata);
 
   ~DecodingImageGenerator() override;
 
   // PaintImageGenerator implementation.
-  bool IsEligibleForAcceleratedDecoding() const override;
   sk_sp<SkData> GetEncodedData() const override;
   bool GetPixels(const SkImageInfo&,
                  void* pixels,
@@ -88,7 +86,8 @@
                       uint32_t lazy_pixel_ref) override;
   SkISize GetSupportedDecodeSize(const SkISize& requested_size) const override;
   PaintImage::ContentId GetContentIdForFrame(size_t frame_index) const override;
-  PaintImage::ImageType GetImageType() const override { return image_type_; }
+  const cc::ImageHeaderMetadata* GetMetadataForDecodeAcceleration()
+      const override;
 
  private:
   DecodingImageGenerator(scoped_refptr<ImageFrameGenerator>,
@@ -97,19 +96,20 @@
                          WebVector<FrameMetadata>,
                          PaintImage::ContentId,
                          bool all_data_received,
-                         bool is_eligible_for_accelerated_decoding,
                          bool can_yuv_decode,
-                         PaintImage::ImageType image_type);
+                         const cc::ImageHeaderMetadata& image_metadata);
 
   scoped_refptr<ImageFrameGenerator> frame_generator_;
   const scoped_refptr<SegmentReader> data_;  // Data source.
   const bool all_data_received_;
-  const bool is_eligible_for_accelerated_decoding_;
   const bool can_yuv_decode_;
   const PaintImage::ContentId complete_frame_content_id_;
-  // The image file kind as returned by the underlying decoder and
-  // translated into PaintImage::ImageType.
-  const PaintImage::ImageType image_type_;
+
+  // Image metadata, such as format (e.g. Jpeg or WebP), YUV subsampling factor
+  // (e.g. 444, 422, 420, etc.), size, and format-specific information that is
+  // useful for deciding which kind of decoding can be used (i.e. hardware
+  // acceleration or normal).
+  const cc::ImageHeaderMetadata image_metadata_;
 
   DISALLOW_COPY_AND_ASSIGN(DecodingImageGenerator);
 };
diff --git a/third_party/blink/renderer/platform/graphics/deferred_image_decoder.cc b/third_party/blink/renderer/platform/graphics/deferred_image_decoder.cc
index cce1f69..6141df1 100644
--- a/third_party/blink/renderer/platform/graphics/deferred_image_decoder.cc
+++ b/third_party/blink/renderer/platform/graphics/deferred_image_decoder.cc
@@ -233,11 +233,14 @@
   // common, so we avoid worrying about this with the line below.
   can_yuv_decode_ &= !incremental_decode_needed_.value();
 
+  DCHECK(image_metadata_);
+  image_metadata_->all_data_received_prior_to_decode =
+      !incremental_decode_needed_.value();
+
   auto generator = DecodingImageGenerator::Create(
       frame_generator_, info, std::move(segment_reader), std::move(frames),
-      complete_frame_content_id_, all_data_received_,
-      !incremental_decode_needed_.value() /* able to do accelerated decoding */,
-      can_yuv_decode_, image_type);
+      complete_frame_content_id_, all_data_received_, can_yuv_decode_,
+      *image_metadata_);
   first_decoding_generator_created_ = true;
 
   size_t image_byte_size = ByteSize();
@@ -420,6 +423,9 @@
       metadata_decoder_->CanDecodeToYUV() && all_data_received_ &&
       !frame_generator_->IsMultiFrame();
 
+  if (!image_metadata_)
+    image_metadata_ = metadata_decoder_->MakeMetadataForDecodeAcceleration();
+
   // If we've received all of the data, then we can reset the metadata decoder,
   // since everything we care about should now be stored in |frame_data_|.
   if (all_data_received_) {
diff --git a/third_party/blink/renderer/platform/graphics/deferred_image_decoder.h b/third_party/blink/renderer/platform/graphics/deferred_image_decoder.h
index 8f590958..d7a069b 100644
--- a/third_party/blink/renderer/platform/graphics/deferred_image_decoder.h
+++ b/third_party/blink/renderer/platform/graphics/deferred_image_decoder.h
@@ -120,6 +120,10 @@
   const PaintImage::ContentId complete_frame_content_id_;
   base::Optional<bool> incremental_decode_needed_;
 
+  // Caches an image's metadata so it can outlive |metadata_decoder_| after all
+  // data is received in cases where multiple generators are created.
+  base::Optional<cc::ImageHeaderMetadata> image_metadata_;
+
   // Caches frame state information.
   Vector<DeferredFrameData> frame_data_;
   scoped_refptr<ImageFrameGenerator> frame_generator_;
diff --git a/third_party/blink/renderer/platform/graphics/deferred_image_decoder_test.cc b/third_party/blink/renderer/platform/graphics/deferred_image_decoder_test.cc
index eb53eebe..da3ee02 100644
--- a/third_party/blink/renderer/platform/graphics/deferred_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/graphics/deferred_image_decoder_test.cc
@@ -199,47 +199,50 @@
   EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), bitmap_.getColor(0, 0));
 }
 
-TEST_F(DeferredImageDecoderTest, isEligibleForHardwareDecodingNonIncremental) {
-  // The image is received completely. This is okay for hardware decoding since
-  // it's assumed that the software decoder hasn't done any work.
+TEST_F(DeferredImageDecoderTest, allDataReceivedPriorToDecodeNonIncrementally) {
+  // The image is received completely at once.
   lazy_decoder_->SetData(data_, true /* all_data_received */);
   PaintImage image = CreatePaintImage();
   ASSERT_TRUE(image);
-  EXPECT_TRUE(image.IsEligibleForAcceleratedDecoding());
+  ASSERT_TRUE(image.GetImageHeaderMetadata());
+  EXPECT_TRUE(
+      image.GetImageHeaderMetadata()->all_data_received_prior_to_decode);
 }
 
-TEST_F(DeferredImageDecoderTest, isEligibleForHardwareDecodingIncremental) {
+TEST_F(DeferredImageDecoderTest, allDataReceivedPriorToDecodeIncrementally) {
   // The image is received in two parts, but a PaintImageGenerator is created
-  // only after all the data is received. This is okay for hardware decoding
-  // since it's assumed that the software decoder hasn't done any work before
-  // the PaintImageGenerator is created.
+  // only after all the data is received.
   scoped_refptr<SharedBuffer> partial_data =
       SharedBuffer::Create(data_->Data(), data_->size() - 10);
   lazy_decoder_->SetData(partial_data, false /* all_data_received */);
   lazy_decoder_->SetData(data_, true /* all_data_received */);
   PaintImage image = CreatePaintImage();
   ASSERT_TRUE(image);
-  EXPECT_TRUE(image.IsEligibleForAcceleratedDecoding());
+  ASSERT_TRUE(image.GetImageHeaderMetadata());
+  EXPECT_TRUE(
+      image.GetImageHeaderMetadata()->all_data_received_prior_to_decode);
 }
 
-TEST_F(DeferredImageDecoderTest, isNotEligibleForHardwareDecoding) {
+TEST_F(DeferredImageDecoderTest, notAllDataReceivedPriorToDecode) {
   // The image is received in two parts, and a PaintImageGenerator is created
   // for each one. In real usage, it's likely that the software image decoder
-  // will start working with partial data, so there's no point in using the
-  // hardware accelerator (because if we did, we'd be doing double work: in
-  // software and in hardware).
+  // will start working with partial data.
   scoped_refptr<SharedBuffer> partial_data =
       SharedBuffer::Create(data_->Data(), data_->size() - 10);
   lazy_decoder_->SetData(partial_data, false /* all_data_received */);
   PaintImage image =
       CreatePaintImage(PaintImage::CompletionState::PARTIALLY_DONE);
   ASSERT_TRUE(image);
-  EXPECT_FALSE(image.IsEligibleForAcceleratedDecoding());
+  ASSERT_TRUE(image.GetImageHeaderMetadata());
+  EXPECT_FALSE(
+      image.GetImageHeaderMetadata()->all_data_received_prior_to_decode);
 
   lazy_decoder_->SetData(data_, true /* all_data_received */);
   image = CreatePaintImage();
   ASSERT_TRUE(image);
-  EXPECT_FALSE(image.IsEligibleForAcceleratedDecoding());
+  ASSERT_TRUE(image.GetImageHeaderMetadata());
+  EXPECT_FALSE(
+      image.GetImageHeaderMetadata()->all_data_received_prior_to_decode);
 }
 
 static void RasterizeMain(cc::PaintCanvas* canvas, sk_sp<PaintRecord> record) {
diff --git a/third_party/blink/renderer/platform/image-decoders/DEPS b/third_party/blink/renderer/platform/image-decoders/DEPS
index c40be9e..8bcb951 100644
--- a/third_party/blink/renderer/platform/image-decoders/DEPS
+++ b/third_party/blink/renderer/platform/image-decoders/DEPS
@@ -6,6 +6,7 @@
     "+third_party/blink/renderer/platform/image-decoders",
 
     # Dependencies.
+    "+base/bits.h",
     "+cc/paint/image_animation_count.h",
     "+third_party/blink/renderer/platform/geometry",
     "+third_party/blink/renderer/platform/graphics",
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
index be591272..0571d11 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -32,9 +32,30 @@
 #include "third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace blink {
 
+namespace {
+
+cc::ImageType FileExtensionToImageType(String image_extension) {
+  if (image_extension == "png")
+    return cc::ImageType::kPNG;
+  if (image_extension == "jpg")
+    return cc::ImageType::kJPEG;
+  if (image_extension == "webp")
+    return cc::ImageType::kWEBP;
+  if (image_extension == "gif")
+    return cc::ImageType::kGIF;
+  if (image_extension == "ico")
+    return cc::ImageType::kICO;
+  if (image_extension == "bmp")
+    return cc::ImageType::kBMP;
+  return cc::ImageType::kInvalid;
+}
+
+}  // namespace
+
 const size_t ImageDecoder::kNoDecodedImageByteLimit;
 
 inline bool MatchesJPEGSignature(const char* contents) {
@@ -232,6 +253,17 @@
   return kUndefinedFormat;
 }
 
+cc::ImageHeaderMetadata ImageDecoder::MakeMetadataForDecodeAcceleration()
+    const {
+  DCHECK(IsDecodedSizeAvailable());
+  cc::ImageHeaderMetadata image_metadata{};
+  image_metadata.image_type = FileExtensionToImageType(FilenameExtension());
+  image_metadata.yuv_subsampling = GetYUVSubsampling();
+  image_metadata.image_size = static_cast<gfx::Size>(size_);
+  image_metadata.has_embedded_color_profile = HasEmbeddedColorProfile();
+  return image_metadata;
+}
+
 size_t ImageDecoder::FrameCount() {
   const size_t old_size = frame_buffer_cache_.size();
   const size_t new_size = DecodeFrameCount();
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.h b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
index 2afe9d4a..274c73c 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
@@ -33,6 +33,7 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/graphics/color_behavior.h"
 #include "third_party/blink/renderer/platform/graphics/image_orientation.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_image.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_animation.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_frame.h"
 #include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
@@ -243,6 +244,12 @@
     return SkYUVColorSpace::kIdentity_SkYUVColorSpace;
   }
 
+  // Returns the information required to decide whether or not hardware
+  // acceleration can be used to decode this image. Callers of this function
+  // must ensure the header was successfully parsed prior to calling this
+  // method, i.e., IsDecodedSizeAvailable() must return true.
+  virtual cc::ImageHeaderMetadata MakeMetadataForDecodeAcceleration() const;
+
   // This will only differ from size() for ICO (where each frame is a
   // different icon) or other formats where different frames are different
   // sizes. This does NOT differ from size() for GIF or WebP, since
@@ -499,6 +506,11 @@
   std::unique_ptr<ImagePlanes> image_planes_;
 
  private:
+  // The YUV subsampling of the image.
+  virtual cc::YUVSubsampling GetYUVSubsampling() const {
+    return cc::YUVSubsampling::kUnknown;
+  }
+
   // Some code paths compute the size of the image as "width * height * 4 or 8"
   // and return it as a (signed) int.  Avoid overflow.
   inline bool SizeCalculationMayOverflow(unsigned width,
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
index 22df689..142bc4d5 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
@@ -39,6 +39,8 @@
 
 #include <memory>
 
+#include "base/bits.h"
+#include "base/numerics/safe_conversions.h"
 #include "build/build_config.h"
 #include "third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
@@ -81,19 +83,9 @@
 // JPEG only supports a denominator of 8.
 const unsigned g_scale_denominator = 8;
 
-enum yuv_subsampling {
-  YUV_UNKNOWN,
-  YUV_410,
-  YUV_411,
-  YUV_420,
-  YUV_422,
-  YUV_440,
-  YUV_444
-};
-
 // Extracts the YUV subsampling format of an image given |info| which is assumed
 // to have gone through a jpeg_read_header() call.
-yuv_subsampling YuvSubsampling(const jpeg_decompress_struct& info) {
+cc::YUVSubsampling YuvSubsampling(const jpeg_decompress_struct& info) {
   if (info.jpeg_color_space == JCS_YCbCr && info.num_components == 3 &&
       info.comp_info && info.comp_info[1].h_samp_factor == 1 &&
       info.comp_info[1].v_samp_factor == 1 &&
@@ -104,29 +96,24 @@
     if (v == 1) {
       switch (h) {
         case 1:
-          return YUV_444;
+          return cc::YUVSubsampling::k444;
         case 2:
-          return YUV_422;
+          return cc::YUVSubsampling::k422;
         case 4:
-          return YUV_411;
-        default:
-          break;
+          return cc::YUVSubsampling::k411;
       }
     } else if (v == 2) {
       switch (h) {
         case 1:
-          return YUV_440;
+          return cc::YUVSubsampling::k440;
         case 2:
-          return YUV_420;
+          return cc::YUVSubsampling::k420;
         case 4:
-          return YUV_410;
-        default:
-          break;
+          return cc::YUVSubsampling::k410;
       }
     }
   }
-
-  return YUV_UNKNOWN;
+  return cc::YUVSubsampling::kUnknown;
 }
 
 // Extracts the JPEG color space of an image for UMA purposes given |info| which
@@ -150,19 +137,19 @@
       return blink::BitmapImageMetrics::JpegColorSpace::kYCCK;
     case JCS_YCbCr:
       switch (YuvSubsampling(info)) {
-        case YUV_444:
+        case cc::YUVSubsampling::k444:
           return blink::BitmapImageMetrics::JpegColorSpace::kYCbCr444;
-        case YUV_422:
+        case cc::YUVSubsampling::k422:
           return blink::BitmapImageMetrics::JpegColorSpace::kYCbCr422;
-        case YUV_411:
+        case cc::YUVSubsampling::k411:
           return blink::BitmapImageMetrics::JpegColorSpace::kYCbCr411;
-        case YUV_440:
+        case cc::YUVSubsampling::k440:
           return blink::BitmapImageMetrics::JpegColorSpace::kYCbCr440;
-        case YUV_420:
+        case cc::YUVSubsampling::k420:
           return blink::BitmapImageMetrics::JpegColorSpace::kYCbCr420;
-        case YUV_410:
+        case cc::YUVSubsampling::k410:
           return blink::BitmapImageMetrics::JpegColorSpace::kYCbCr410;
-        case YUV_UNKNOWN:
+        case cc::YUVSubsampling::kUnknown:
           return blink::BitmapImageMetrics::JpegColorSpace::kYCbCrOther;
       }
       NOTREACHED();
@@ -465,8 +452,8 @@
             // TODO(crbug.com/919627): is the info_.scale_denom <= 8 actually
             // needed?
             info_.out_color_space = rgbOutputColorSpace();
-            if (decoder_->HasImagePlanes() && (info_.scale_denom <= 8) &&
-                (YuvSubsampling(info_) != YUV_UNKNOWN))
+            if (decoder_->HasImagePlanes() && info_.scale_denom <= 8 &&
+                (YuvSubsampling(info_) != cc::YUVSubsampling::kUnknown))
               override_color_space = JCS_YCbCr;
             break;
           case JCS_GRAYSCALE:
@@ -946,6 +933,27 @@
   return supported_decode_sizes_;
 }
 
+cc::ImageHeaderMetadata JPEGImageDecoder::MakeMetadataForDecodeAcceleration()
+    const {
+  cc::ImageHeaderMetadata image_metadata =
+      ImageDecoder::MakeMetadataForDecodeAcceleration();
+  image_metadata.jpeg_is_progressive = reader_->Info()->buffered_image;
+
+  // Calculate the coded size of the image.
+  const size_t mcu_width =
+      base::checked_cast<size_t>(reader_->Info()->comp_info->h_samp_factor * 8);
+  const size_t mcu_height =
+      base::checked_cast<size_t>(reader_->Info()->comp_info->v_samp_factor * 8);
+  const int coded_width = base::checked_cast<int>(base::bits::Align(
+      base::checked_cast<size_t>(image_metadata.image_size.width()),
+      mcu_width));
+  const int coded_height = base::checked_cast<int>(base::bits::Align(
+      base::checked_cast<size_t>(image_metadata.image_size.height()),
+      mcu_height));
+  image_metadata.coded_size = gfx::Size(coded_width, coded_height);
+  return image_metadata;
+}
+
 // At the moment we support only JCS_RGB and JCS_CMYK values of the
 // J_COLOR_SPACE enum.
 // If you need a specific implementation for other J_COLOR_SPACE values,
@@ -1155,6 +1163,13 @@
   return decoder->FrameIsDecodedAtIndex(0);
 }
 
+cc::YUVSubsampling JPEGImageDecoder::GetYUVSubsampling() const {
+  DCHECK(reader_->Info());
+  // reader_->Info() should have gone through a jpeg_read_header() call.
+  DCHECK(IsDecodedSizeAvailable());
+  return YuvSubsampling(*reader_->Info());
+}
+
 void JPEGImageDecoder::Decode(bool only_size) {
   if (Failed())
     return;
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h
index b43dcfe..680103421 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h
@@ -78,6 +78,8 @@
   // ImageDecoder:
   void DecodeSize() override { Decode(true); }
   void Decode(size_t) override { Decode(false); }
+  cc::YUVSubsampling GetYUVSubsampling() const override;
+  cc::ImageHeaderMetadata MakeMetadataForDecodeAcceleration() const override;
 
   // Decodes the image.  If |only_size| is true, stops decoding after
   // calculating the image size.  If decoding fails but there is no more
diff --git a/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.cc
index f4c60723..a75f3738 100644
--- a/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.cc
@@ -28,6 +28,8 @@
 
 #include "third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h"
 
+#include <string.h>
+
 #include "base/feature_list.h"
 #include "build/build_config.h"
 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
@@ -121,6 +123,20 @@
   kCountWebPFileFormats
 };
 
+// Validates that |blob| is a simple lossy WebP image. Note that this explicitly
+// checks "WEBPVP8 " to exclude extended lossy WebPs that don't actually use any
+// extended features.
+//
+// TODO(crbug.com/1009237): consider combining this with the logic to detect
+// WebPs that can be decoded to YUV.
+bool IsSimpleLossyWebPImage(const sk_sp<SkData>& blob) {
+  if (blob->size() < 20UL)
+    return false;
+  DCHECK(blob->bytes());
+  return !memcmp(blob->bytes(), "RIFF", 4) &&
+         !memcmp(blob->bytes() + 8UL, "WEBPVP8 ", 8);
+}
+
 // This method parses |blob|'s header and emits a UMA with the file format, as
 // defined by WebP, see WebPFileFormat.
 void UpdateWebPFileFormatUMA(const sk_sp<SkData>& blob) {
@@ -441,6 +457,17 @@
   return SkYUVColorSpace::kRec601_SkYUVColorSpace;
 }
 
+cc::YUVSubsampling WEBPImageDecoder::GetYUVSubsampling() const {
+  DCHECK(consolidated_data_);
+  if (IsSimpleLossyWebPImage(consolidated_data_))
+    return cc::YUVSubsampling::k420;
+  // It is possible for a non-simple lossy WebP to also be YUV 4:2:0. However,
+  // we're being conservative here because this is currently only used for
+  // hardware decode acceleration, and WebPs other than simple lossy are not
+  // supported in that path anyway.
+  return cc::YUVSubsampling::kUnknown;
+}
+
 bool WEBPImageDecoder::CanReusePreviousFrameBuffer(size_t frame_index) const {
   DCHECK(frame_index < frame_buffer_cache_.size());
   return frame_buffer_cache_[frame_index].GetAlphaBlendSource() !=
@@ -767,4 +794,15 @@
   }
 }
 
+cc::ImageHeaderMetadata WEBPImageDecoder::MakeMetadataForDecodeAcceleration()
+    const {
+  cc::ImageHeaderMetadata image_metadata =
+      ImageDecoder::MakeMetadataForDecodeAcceleration();
+
+  DCHECK(consolidated_data_);
+  image_metadata.webp_is_non_extended_lossy =
+      IsSimpleLossyWebPImage(consolidated_data_);
+  return image_metadata;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h b/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h
index 6aed2aeb..1c40d37 100644
--- a/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder.h
@@ -61,6 +61,8 @@
   void Decode(size_t) override;
   void DecodeToYUV() override;
   SkYUVColorSpace GetYUVColorSpace() const override;
+  cc::YUVSubsampling GetYUVSubsampling() const override;
+  cc::ImageHeaderMetadata MakeMetadataForDecodeAcceleration() const override;
 
   WEBP_CSP_MODE RGBOutputMode();
   // Returns true if the image data received so far (as stored in
diff --git a/third_party/blink/renderer/platform/instrumentation/BUILD.gn b/third_party/blink/renderer/platform/instrumentation/BUILD.gn
index 4431cce..795b1a25 100644
--- a/third_party/blink/renderer/platform/instrumentation/BUILD.gn
+++ b/third_party/blink/renderer/platform/instrumentation/BUILD.gn
@@ -35,6 +35,7 @@
   ]
 
   deps = [
+    "//components/performance_manager/public/mojom:mojom_blink",
     "//services/service_manager/public/cpp",
   ]
 }
diff --git a/third_party/blink/renderer/platform/instrumentation/DEPS b/third_party/blink/renderer/platform/instrumentation/DEPS
index 056ae2a3..1b9aae2 100644
--- a/third_party/blink/renderer/platform/instrumentation/DEPS
+++ b/third_party/blink/renderer/platform/instrumentation/DEPS
@@ -12,6 +12,7 @@
     "+base/strings",
     "+base/trace_event",
     "+base/values.h",
+    "+components/performance_manager/public/mojom",
     "+skia/ext/skia_trace_memory_dump_impl.h",
 
     "+third_party/blink/renderer/platform/fonts/font_global_context.h",
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
index 47b49d2..29c7ca3b 100644
--- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
+++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
@@ -14,7 +14,7 @@
 
 namespace {
 
-using resource_coordinator::mojom::InterventionPolicy;
+using performance_manager::mojom::InterventionPolicy;
 
 }  // namespace
 
@@ -41,7 +41,7 @@
 }
 
 void DocumentResourceCoordinator::SetLifecycleState(
-    resource_coordinator::mojom::LifecycleState state) {
+    performance_manager::mojom::LifecycleState state) {
   service_->SetLifecycleState(state);
 }
 
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
index f5b88f8..5921753 100644
--- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
+++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
@@ -8,8 +8,8 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom-blink.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom-blink.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
@@ -29,10 +29,10 @@
   ~DocumentResourceCoordinator();
 
   void SetNetworkAlmostIdle();
-  void SetLifecycleState(resource_coordinator::mojom::LifecycleState);
+  void SetLifecycleState(performance_manager::mojom::LifecycleState);
   void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload);
   void SetOriginTrialFreezePolicy(
-      resource_coordinator::mojom::InterventionPolicy policy);
+      performance_manager::mojom::InterventionPolicy policy);
   // A one way switch that marks a frame as being an adframe.
   void SetIsAdFrame();
   void OnNonPersistentNotificationCreated();
@@ -40,7 +40,7 @@
  private:
   explicit DocumentResourceCoordinator(service_manager::InterfaceProvider*);
 
-  mojo::Remote<resource_coordinator::mojom::blink::DocumentCoordinationUnit>
+  mojo::Remote<performance_manager::mojom::blink::DocumentCoordinationUnit>
       service_;
 
   DISALLOW_COPY_AND_ASSIGN(DocumentResourceCoordinator);
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.cc b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.cc
index decffea..42437f6 100644
--- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.cc
+++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.cc
@@ -27,7 +27,7 @@
   DCHECK(platform);
 
   mojo::PendingRemote<
-      resource_coordinator::mojom::blink::ProcessCoordinationUnit>
+      performance_manager::mojom::blink::ProcessCoordinationUnit>
       remote;
   platform->GetBrowserInterfaceBrokerProxy()->GetInterface(
       remote.InitWithNewPipeAndPassReceiver());
@@ -49,7 +49,7 @@
 
 RendererResourceCoordinator::RendererResourceCoordinator(
     mojo::PendingRemote<
-        resource_coordinator::mojom::blink::ProcessCoordinationUnit> remote) {
+        performance_manager::mojom::blink::ProcessCoordinationUnit> remote) {
   service_.Bind(std::move(remote));
 }
 
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h
index 876fb1a..43795cc 100644
--- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h
+++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h
@@ -6,8 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_INSTRUMENTATION_RESOURCE_COORDINATOR_RENDERER_RESOURCE_COORDINATOR_H_
 
 #include "base/macros.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom-blink.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom-blink.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
@@ -36,9 +36,9 @@
  private:
   explicit RendererResourceCoordinator(
       mojo::PendingRemote<
-          resource_coordinator::mojom::blink::ProcessCoordinationUnit> remote);
+          performance_manager::mojom::blink::ProcessCoordinationUnit> remote);
 
-  mojo::Remote<resource_coordinator::mojom::blink::ProcessCoordinationUnit>
+  mojo::Remote<performance_manager::mojom::blink::ProcessCoordinationUnit>
       service_;
 
   DISALLOW_COPY_AND_ASSIGN(RendererResourceCoordinator);
diff --git a/third_party/blink/renderer/platform/p2p/mdns_responder_adapter.cc b/third_party/blink/renderer/platform/p2p/mdns_responder_adapter.cc
index 70a2730a..13e028d 100644
--- a/third_party/blink/renderer/platform/p2p/mdns_responder_adapter.cc
+++ b/third_party/blink/renderer/platform/p2p/mdns_responder_adapter.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "jingle/glue/utils.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
@@ -39,27 +40,27 @@
 }  // namespace
 
 MdnsResponderAdapter::MdnsResponderAdapter() {
-  network::mojom::blink::MdnsResponderPtr client;
-  auto request = mojo::MakeRequest(&client);
-  thread_safe_client_ =
-      network::mojom::blink::ThreadSafeMdnsResponderPtr::Create(
+  mojo::PendingRemote<network::mojom::blink::MdnsResponder> client;
+  auto receiver = client.InitWithNewPipeAndPassReceiver();
+  shared_remote_client_ =
+      mojo::SharedRemote<network::mojom::blink::MdnsResponder>(
           std::move(client));
   blink::Platform::Current()->GetBrowserInterfaceBrokerProxy()->GetInterface(
-      std::move(request));
+      std::move(receiver));
 }
 
 MdnsResponderAdapter::~MdnsResponderAdapter() = default;
 
 void MdnsResponderAdapter::CreateNameForAddress(const rtc::IPAddress& addr,
                                                 NameCreatedCallback callback) {
-  thread_safe_client_->get()->CreateNameForAddress(
+  shared_remote_client_->CreateNameForAddress(
       jingle_glue::RtcIPAddressToNetIPAddress(addr),
       base::BindOnce(&OnNameCreatedForAddress, callback, addr));
 }
 
 void MdnsResponderAdapter::RemoveNameForAddress(const rtc::IPAddress& addr,
                                                 NameRemovedCallback callback) {
-  thread_safe_client_->get()->RemoveNameForAddress(
+  shared_remote_client_->RemoveNameForAddress(
       jingle_glue::RtcIPAddressToNetIPAddress(addr),
       base::BindOnce(&OnNameRemovedForAddress, callback));
 }
diff --git a/third_party/blink/renderer/platform/p2p/mdns_responder_adapter.h b/third_party/blink/renderer/platform/p2p/mdns_responder_adapter.h
index b829832fc..53f045a 100644
--- a/third_party/blink/renderer/platform/p2p/mdns_responder_adapter.h
+++ b/third_party/blink/renderer/platform/p2p/mdns_responder_adapter.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_P2P_MDNS_RESPONDER_ADAPTER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_P2P_MDNS_RESPONDER_ADAPTER_H_
 
+#include "mojo/public/cpp/bindings/shared_remote.h"
 #include "services/network/public/mojom/mdns_responder.mojom-blink.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/webrtc/rtc_base/mdns_responder_interface.h"
@@ -34,8 +35,8 @@
                             NameRemovedCallback callback) override;
 
  private:
-  scoped_refptr<network::mojom::blink::ThreadSafeMdnsResponderPtr>
-      thread_safe_client_;
+  mojo::SharedRemote<network::mojom::blink::MdnsResponder>
+      shared_remote_client_;
 
   DISALLOW_COPY_AND_ASSIGN(MdnsResponderAdapter);
 };
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 9d9f333..e98f1e7f 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -450,6 +450,10 @@
       status: "experimental",
     },
     {
+      name: "CSSOMViewScrollCoordinates",
+      status: "experimental",
+    },
+    {
       name: "CSSPaintAPIArguments",
       status: "experimental",
       depends_on: ["CSSVariables2"],
diff --git a/third_party/blink/renderer/platform/scheduler/test/web_fake_thread_scheduler.cc b/third_party/blink/renderer/platform/scheduler/test/web_fake_thread_scheduler.cc
index b28591d..17766c3 100644
--- a/third_party/blink/renderer/platform/scheduler/test/web_fake_thread_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/test/web_fake_thread_scheduler.cc
@@ -6,6 +6,7 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -33,7 +34,7 @@
 
 scoped_refptr<base::SingleThreadTaskRunner>
 WebFakeThreadScheduler::InputTaskRunner() {
-  return nullptr;
+  return base::ThreadTaskRunnerHandle::Get();
 }
 
 scoped_refptr<base::SingleThreadTaskRunner>
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNGFragmentItem b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNGFragmentItem
index 7575ac9..401398d 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNGFragmentItem
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNGFragmentItem
@@ -1879,7 +1879,6 @@
 crbug.com/982194 virtual/layout_ng_experimental/printing/page-count-layout-overflow.html [ Failure ]
 crbug.com/982194 virtual/layout_ng_experimental/printing/return-from-printing-mode.html [ Failure ]
 crbug.com/982194 virtual/layout_ng_experimental/printing/css2.1/page-break-inside-000.html [ Failure ]
-crbug.com/982194 virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/scrollbar-occluded-by-div.html [ Crash ]
 crbug.com/982194 virtual/mouseevent_fractional/fast/events/anchor-image-scrolled-x-y.html [ Timeout ]
 crbug.com/982194 virtual/mouseevent_fractional/fast/events/attribute-listener-deletion-crash.html [ Crash ]
 crbug.com/982194 virtual/mouseevent_fractional/fast/events/autoscroll-disabled-in-fix.html [ Crash ]
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 94fd890..164c804 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -75,6 +75,10 @@
 [ Mac ] fast/forms/calendar-picker/month-open-picker-with-f4-key.html [ WontFix ]
 [ Mac ] fast/forms/calendar-picker/week-open-picker-with-f4-key.html [ WontFix ]
 
+# These tests are specific to Windows.
+crbug.com/1012590 [ Mac ] fast/overflow/rtl-scrollbar-drag-origin.html [ WontFix ]
+crbug.com/1012590 [ Linux ] fast/overflow/rtl-scrollbar-drag-origin.html [ WontFix ]
+
 # Mac does not have menu key.
 [ Mac ] editing/spelling/spelling-on-context-menu-key.html [ WontFix ]
 [ Mac ] fast/events/context-menu-key-shift-f10-modifiers.html [ WontFix ]
@@ -103,8 +107,6 @@
 [ Mac ]   virtual/scroll_customization/fast/scrolling/scrollbars/scrollbar-thumb-snapping.html [ WontFix ]
 [ Linux ] virtual/threaded/fast/scrolling/scrollbars/scrollbar-thumb-snapping.html [ WontFix ]
 [ Mac ]   virtual/threaded/fast/scrolling/scrollbars/scrollbar-thumb-snapping.html [ WontFix ]
-[ Linux ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/scrollbar-thumb-snapping.html [ WontFix ]
-[ Mac ]   virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/scrollbar-thumb-snapping.html [ WontFix ]
 
 
 # These tests are specific to Linux.
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index 38a1e1f..fc8458b 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -640,7 +640,6 @@
 crbug.com/980804 virtual/compositor_threaded_scrollbar_scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ]
 crbug.com/980804 virtual/scroll_customization/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ]
 crbug.com/980804 virtual/threaded/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ]
-crbug.com/980804 virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ]
 
 crbug.com/983642 virtual/gpu/fast/canvas/canvas-composite-alpha.html [ Slow ]
 crbug.com/983642 [ Mac Debug ] fast/canvas/canvas-composite-alpha.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b7651de..9389cec 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -686,6 +686,9 @@
 
 crbug.com/1003506 external/wpt/css/css-flexbox/percentage-heights-007.html [ Failure ]
 
+crbug.com/680331 external/wpt/css/cssom-view/scrollIntoView-sideways-lr-writing-mode-and-rtl-direction.html [ Failure ]
+crbug.com/680331 external/wpt/css/cssom-view/scrollIntoView-sideways-rl-writing-mode-and-rtl-direction.html [ Failure ]
+
 # ====== Layout team owned tests to here ======
 
 # ====== LayoutNG-only failures from here ======
@@ -2831,12 +2834,6 @@
 crbug.com/953847 [ Mac ] virtual/threaded/fast/scrolling/scrollbars/scrollbar-occluded-by-div.html [ Failure ]
 crbug.com/953847 [ Mac ] virtual/threaded/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ]
 crbug.com/953847 [ Mac ] virtual/threaded/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Timeout ]
-crbug.com/953847 [ Mac ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html [ Failure ]
-crbug.com/953847 [ Mac ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html [ Failure ]
-crbug.com/953847 [ Mac ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/scroll-chaining-for-gesture-based-scrolling.html [ Failure ]
-crbug.com/953847 [ Mac ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/scrollbar-occluded-by-div.html [ Failure ]
-crbug.com/953847 [ Mac ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Failure ]
-crbug.com/953847 [ Mac ] virtual/main_thread_scrollbar_gestures/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Timeout ]
 
 # Compositor threaded scrollbar scrolls parent of subscroller.
 # Note: even when fixed will still fail on Mac until crbug.com/953847
@@ -5812,8 +5809,6 @@
 
 # Sheriff 2019-07-30
 crbug.com/987115 [ Win Linux ] virtual/threaded/fast/scrolling/scrollbars/scrollbar-button-gesture-target.html [ Crash Pass Failure ]
-crbug.com/626703 [ Mac ] external/wpt/css/cssom-view/scrollIntoView-sideways-lr-writing-mode-and-rtl-direction.html [ Failure ]
-crbug.com/626703 [ Mac ] external/wpt/css/cssom-view/scrollIntoView-sideways-rl-writing-mode-and-rtl-direction.html [ Failure ]
 
 # Sheriff 2019-07-31
 crbug.com/979422 [ Mac ] fast/borders/border-radius-mask-canvas-with-shadow.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index ef89c18..82ae233 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -546,11 +546,6 @@
              "--enable-prefer-compositing-to-lcd-text"]
   },
   {
-    "prefix": "main_thread_scrollbar_gestures",
-    "base": "fast/scrolling/scrollbars",
-    "args": ["--enable-features=ScrollbarInjectScrollGestures"]
-  },
-  {
     "prefix": "speech-with-unified-autoplay",
     "base": "external/wpt/speech-api",
     "args": ["--autoplay-policy=document-user-activation-required"]
diff --git a/third_party/blink/web_tests/compositing/overflow/rtl-overflow.html b/third_party/blink/web_tests/compositing/overflow/rtl-overflow.html
index 6fee984..9b9604a 100644
--- a/third_party/blink/web_tests/compositing/overflow/rtl-overflow.html
+++ b/third_party/blink/web_tests/compositing/overflow/rtl-overflow.html
@@ -51,7 +51,7 @@
     </div>
   </div>
   <script>
-    document.getElementById('second').scrollLeft = 0;
+    document.getElementById('second').scrollLeft = -600;
   </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/compositing/rtl/rtl-overflow-scrolling.html b/third_party/blink/web_tests/compositing/rtl/rtl-overflow-scrolling.html
index ce10f3f..53e62c3 100644
--- a/third_party/blink/web_tests/compositing/rtl/rtl-overflow-scrolling.html
+++ b/third_party/blink/web_tests/compositing/rtl/rtl-overflow-scrolling.html
@@ -5,7 +5,7 @@
         internals.settings.setPreferCompositingToLCDTextEnabled(true);
 
     function runTest() {
-        document.getElementById("container").scrollLeft = 0;
+        document.getElementById("container").scrollLeft = -715;
     }
 </script>
 <style>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index e9d33fde..cbd0312 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -99471,6 +99471,18 @@
      {}
     ]
    ],
+   "css/filter-effects/morphology-mirrored.html": [
+    [
+     "css/filter-effects/morphology-mirrored.html",
+     [
+      [
+       "/css/filter-effects/reference/green-100x100.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/filter-effects/svg-feflood-001.html": [
     [
      "css/filter-effects/svg-feflood-001.html",
@@ -140515,6 +140527,9 @@
    "css/css-rhythm/OWNERS": [
     []
    ],
+   "css/css-rhythm/line-height-step-dynamic-001-expected.txt": [
+    []
+   ],
    "css/css-rhythm/reference/line-height-step-basic-001.html": [
     []
    ],
@@ -140839,6 +140854,9 @@
    "css/css-shapes/shape-outside/values/shape-margin-005-expected.txt": [
     []
    ],
+   "css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt": [
+    []
+   ],
    "css/css-shapes/shape-outside/values/shape-outside-inset-001-expected.txt": [
     []
    ],
@@ -162091,9 +162109,6 @@
    "infrastructure/metadata/infrastructure/server/wpt-server-websocket.sub.html.ini": [
     []
    ],
-   "infrastructure/metadata/infrastructure/testdriver/actions/__dir__.ini": [
-    []
-   ],
    "infrastructure/metadata/infrastructure/testdriver/actions/actionsWithKeyPressed.html.ini": [
     []
    ],
@@ -317043,24 +317058,6 @@
      {}
     ]
    ],
-   "webxr/xrDevice_supportsSession_immersive.https.html": [
-    [
-     "webxr/xrDevice_supportsSession_immersive.https.html",
-     {}
-    ]
-   ],
-   "webxr/xrDevice_supportsSession_immersive_unsupported.https.html": [
-    [
-     "webxr/xrDevice_supportsSession_immersive_unsupported.https.html",
-     {}
-    ]
-   ],
-   "webxr/xrDevice_supportsSession_non_immersive.https.html": [
-    [
-     "webxr/xrDevice_supportsSession_non_immersive.https.html",
-     {}
-    ]
-   ],
    "webxr/xrFrame_getPose.https.html": [
     [
      "webxr/xrFrame_getPose.https.html",
@@ -337192,7 +337189,7 @@
    "support"
   ],
   "beacon/META.yml": [
-   "94fa75c5178a39d519807ddc2490900d41acae41",
+   "4bd94e32064c78553666424e1d0ee30bca4987fb",
    "support"
   ],
   "beacon/OWNERS": [
@@ -380256,7 +380253,7 @@
    "testharness"
   ],
   "css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-009-expected.txt": [
-   "1b32cf43618de6966339657668d941b520143fa5",
+   "3a100a48575ea7873c6e6b0344c3765be1437d3b",
    "support"
   ],
   "css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-009.html": [
@@ -380264,7 +380261,7 @@
    "testharness"
   ],
   "css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-010-expected.txt": [
-   "1b32cf43618de6966339657668d941b520143fa5",
+   "3a100a48575ea7873c6e6b0344c3765be1437d3b",
    "support"
   ],
   "css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-010.html": [
@@ -389691,6 +389688,10 @@
    "b4c29905ea2f491efd8d0365ac1c5a870e8c4edf",
    "reftest"
   ],
+  "css/css-rhythm/line-height-step-dynamic-001-expected.txt": [
+   "bac9d811062b8f08f1cf6fdb3e8dc7b14f867274",
+   "support"
+  ],
   "css/css-rhythm/line-height-step-dynamic-001.html": [
    "d6f7bd9e78aedccc86c4a7263b99bb262bae9158",
    "testharness"
@@ -391528,7 +391529,7 @@
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-margin-001.html": [
-   "39dea7efe81eeeb728d8e14ad7557dcf40eb82df",
+   "28eca1a6bafc39408d1c623a0b2625cd4da1478b",
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-margin-002-expected.txt": [
@@ -391576,11 +391577,11 @@
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-circle-004.html": [
-   "01f3fc1bffe24359bca75121ebde97c7fd5d9376",
+   "289861ee1502f00a5afa8fb6aafd47c5dc9afd6a",
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-circle-005.html": [
-   "7d90318ec7365a119ad639b936b4127843ae6203",
+   "46cae045c5d0c8f092d15a194b91e4384146a32e",
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-circle-006.html": [
@@ -391607,6 +391608,10 @@
    "7f0571cdd6f3ad67391435f294ede7efaae7f47e",
    "testharness"
   ],
+  "css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt": [
+   "5e2a1630e2e73625f7230a5d319f7b10ce79ad85",
+   "support"
+  ],
   "css/css-shapes/shape-outside/values/shape-outside-computed-shape-000.html": [
    "f79b21a723e6e253df0176e53a4567d8ec9567ab",
    "testharness"
@@ -391632,11 +391637,11 @@
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-ellipse-004.html": [
-   "7617a34bce0c7f90668141a480b487c534a96eed",
+   "1d4aa85a07c304c320ae44a3364d4e7248a3ea26",
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-ellipse-005.html": [
-   "fe5af3b682c8cd60e3e10278af3aa53ed108d6ba",
+   "5acb994191258c4b8ec02d70309da76cbbc7fc52",
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-ellipse-006.html": [
@@ -391684,7 +391689,7 @@
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-inset-003.html": [
-   "9b420707fe2e292ddec8810f4c185aaa574b3b5b",
+   "3ffc2af981672a7ac018eefb20eb5b750644c609",
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-inset-004.html": [
@@ -391728,7 +391733,7 @@
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-polygon-004.html": [
-   "c9623a2e5bd4f218c1b43a4679cb817a647c77c4",
+   "e9ecf2df599b0258329d5af6a3c09ee8368f1222",
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-polygon-005.html": [
@@ -391740,7 +391745,7 @@
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-shape-arguments-000.html": [
-   "02d5bc78d9a509bec3d77a90b4736ad7376ddf12",
+   "08d5d471de6b93b4446673f9931a976bcbcf1ce8",
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-shape-arguments-001.html": [
@@ -391768,7 +391773,7 @@
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/support/parsing-utils.js": [
-   "118a11453337731f380063b736380c2c8610ae81",
+   "abadbf7066695ad1f754540c9bac75b2809c8c4c",
    "support"
   ],
   "css/css-shapes/spec-examples/reference/shape-outside-001-ref.html": [
@@ -421123,6 +421128,10 @@
    "4fc02f16719d0733e4cba87d8d229fe6ed15e6aa",
    "support"
   ],
+  "css/filter-effects/morphology-mirrored.html": [
+   "f0338e180344f341db60ab0710bdcdb71e8853b7",
+   "reftest"
+  ],
   "css/filter-effects/parsing/backdrop-filter-computed.html": [
    "5e8ce6bae680c84ef49e882309a573113ffc7b1e",
    "testharness"
@@ -439836,7 +439845,7 @@
    "testharness"
   ],
   "hr-time/META.yml": [
-   "2be354920aa140a72bc62ea2273f5d975eab8d46",
+   "779d5b4af08428c45023fc9d519ab0830d866a87",
    "support"
   ],
   "hr-time/OWNERS": [
@@ -460987,10 +460996,6 @@
    "2cc364b610987ad5938c822287eb76079c2af2a3",
    "support"
   ],
-  "infrastructure/metadata/infrastructure/testdriver/actions/__dir__.ini": [
-   "2bac0b50db727ddc70b90ac3fb443954319723ef",
-   "support"
-  ],
   "infrastructure/metadata/infrastructure/testdriver/actions/actionsWithKeyPressed.html.ini": [
    "b9465c066c7657a1ea00e316dddf1b7aaa854ef3",
    "support"
@@ -468068,7 +468073,7 @@
    "support"
   ],
   "navigation-timing/META.yml": [
-   "c09a6e03fd19f5a405b391c2c4671df6ff04edf1",
+   "bfb0e0f1f67a9c6aa2e7e921b09e85f8d970b290",
    "support"
   ],
   "navigation-timing/OWNERS": [
@@ -475236,7 +475241,7 @@
    "support"
   ],
   "page-visibility/META.yml": [
-   "509936c371b7de3e7e0e5f7e41d10cffba9f5d2a",
+   "9b9aea8e8b11bf98dd23c8e161e3a7d701da2aba",
    "support"
   ],
   "page-visibility/OWNERS": [
@@ -476024,7 +476029,7 @@
    "manual"
   ],
   "performance-timeline/META.yml": [
-   "46f16ae5f31aa388cfd1f7ff759a5df44d17fd0a",
+   "89fae1db0d9b7afd202737e34754b4e893298d49",
    "support"
   ],
   "performance-timeline/OWNERS": [
@@ -490052,7 +490057,7 @@
    "testharness"
   ],
   "resource-timing/META.yml": [
-   "76176970d4d93e6a66bf2bc62aec5dd62ccd12c1",
+   "662c42cb664219dee159fd248e1446c041a4bc93",
    "support"
   ],
   "resource-timing/OWNERS": [
@@ -499740,7 +499745,7 @@
    "support"
   ],
   "timing-entrytypes-registry/META.yml": [
-   "c09a6e03fd19f5a405b391c2c4671df6ff04edf1",
+   "bfb0e0f1f67a9c6aa2e7e921b09e85f8d970b290",
    "support"
   ],
   "timing-entrytypes-registry/registry.any.js": [
@@ -499892,7 +499897,7 @@
    "support"
   ],
   "tools/ci/manifest_build.py": [
-   "ade17d6be40d80751de12b0d462a8f531bbe9059",
+   "6400bfd5e4837f44599310127baf6d0905df3416",
    "support"
   ],
   "tools/ci/run_tc.py": [
@@ -508892,7 +508897,7 @@
    "testharness"
   ],
   "user-timing/META.yml": [
-   "a97a31d766bd96f0030a047632c3342c70abf3d8",
+   "5cb2a789c09c89b7c1029551e646b3f240e80c2a",
    "support"
   ],
   "user-timing/OWNERS": [
@@ -510452,7 +510457,7 @@
    "support"
   ],
   "web-share/share-sharePromise-internal-slot.https.html": [
-   "5a71eaa4abf359008d84d1f219083ec1a91a6458",
+   "1478158a0c4efe365ae4a471f905d82a7b1fff8d",
    "testharness"
   ],
   "web-share/share-simple-manual.https.html": [
@@ -518903,18 +518908,6 @@
    "9fa8c31d63aab6f74886b55596ff63911018f51e",
    "testharness"
   ],
-  "webxr/xrDevice_supportsSession_immersive.https.html": [
-   "fd0827a526ef01299eeccd94f93f131e4014cd7b",
-   "testharness"
-  ],
-  "webxr/xrDevice_supportsSession_immersive_unsupported.https.html": [
-   "1d63a2b1c3a254d999473bc507453095c4243a08",
-   "testharness"
-  ],
-  "webxr/xrDevice_supportsSession_non_immersive.https.html": [
-   "b376495d765106fcb1435c3e60c0fa6e167d9c71",
-   "testharness"
-  ],
   "webxr/xrFrame_getPose.https.html": [
    "71ca78abb48cf12cb41e8249289a06eddc7eae94",
    "testharness"
diff --git a/third_party/blink/web_tests/external/wpt/animation-worklet/scroll-timeline-writing-modes.https.html b/third_party/blink/web_tests/external/wpt/animation-worklet/scroll-timeline-writing-modes.https.html
index 189bb9f0..eb8e6fd 100644
--- a/third_party/blink/web_tests/external/wpt/animation-worklet/scroll-timeline-writing-modes.https.html
+++ b/third_party/blink/web_tests/external/wpt/animation-worklet/scroll-timeline-writing-modes.https.html
@@ -108,11 +108,11 @@
   const elements = createTestDOM(true, 'vertical-rl', 'ltr');
   const animation = createAndPlayTestAnimation(elements, 'block');
 
-  // Move the scroller to the 75% point. Since it is vertical-rl, this is
-  // equivalent to the 25% point for the ScrollTimeline.
+  // Move the scroller to the left 25% point, since it is vertical-rl,
+  // i.e leftwards overflow direction, scrollLeft is -25% point.
   const maxScroll =
       elements.scroller.scrollWidth - elements.scroller.clientWidth;
-  elements.scroller.scrollLeft = 0.75 * maxScroll;
+  elements.scroller.scrollLeft = -0.25 * maxScroll;
 
   waitForNotNullLocalTime(animation).then(t.step_func_done(() => {
     assert_equals(
@@ -124,11 +124,11 @@
   const elements = createTestDOM(true, 'horizontal-tb', 'rtl');
   const animation = createAndPlayTestAnimation(elements, 'inline');
 
-  // Move the scroller to the 75% point. Since it is direction: rtl, this is
-  // equivalent to the 25% point for the ScrollTimeline.
+  // Move the scroller to the left 25% point, since it is direction: rtl,
+  // i.e leftwards overflow direction, scrollLeft is -25% point.
   const maxScroll =
       elements.scroller.scrollWidth - elements.scroller.clientWidth;
-  elements.scroller.scrollLeft = 0.75 * maxScroll;
+  elements.scroller.scrollLeft = -0.25 * maxScroll;
 
   waitForNotNullLocalTime(animation).then(t.step_func_done(() => {
     assert_equals(
@@ -155,11 +155,11 @@
   const elements = createTestDOM(false, 'vertical-lr', 'rtl');
   const animation = createAndPlayTestAnimation(elements, 'inline');
 
-  // Move the scroller to the 75% point. Since this is a vertical writing mode
-  // and direction: rtl, this is 25% of the ScrollTimeline currentTime.
+  // Move the scroller to the top 25% point, since it is a vertical-lr writing mode
+  // and direction: rtl, i.e upwards overflow direction, scrollTop is -25% point.
   const maxScroll =
       elements.scroller.scrollHeight - elements.scroller.clientHeight;
-  elements.scroller.scrollTop = 0.75 * maxScroll;
+  elements.scroller.scrollTop = -0.25 * maxScroll;
 
   waitForNotNullLocalTime(animation).then(t.step_func_done(() => {
     assert_equals(
diff --git a/third_party/blink/web_tests/external/wpt/beacon/META.yml b/third_party/blink/web_tests/external/wpt/beacon/META.yml
index 94fa75c..4bd94e3 100644
--- a/third_party/blink/web_tests/external/wpt/beacon/META.yml
+++ b/third_party/blink/web_tests/external/wpt/beacon/META.yml
@@ -1,4 +1,3 @@
 spec: https://w3c.github.io/beacon/
 suggested_reviewers:
-  - toddreifsteck
   - igrigorik
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-auto-ref.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-auto-ref.html
index e83ba52..590b533 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-auto-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-auto-ref.html
@@ -166,8 +166,8 @@
 }
 nodes = document.querySelectorAll(".rtl > .row-reverse");
 for (var i = 0; i < nodes.length; i++) {
-  nodes[i].scrollLeft = 0;
-  nodes[i].scrollTop = 0;
+  nodes[i].scrollLeft = -10000;
+  nodes[i].scrollTop = -10000;
 }
 nodes = document.querySelectorAll(".column-reverse");
 for (var i = 0; i < nodes.length; i++) {
@@ -176,7 +176,7 @@
 }
 nodes = document.querySelectorAll(".flipped-blocks > .column-reverse");
 for (var i = 0; i < nodes.length; i++) {
-  nodes[i].scrollLeft = 0;
+  nodes[i].scrollLeft = -10000;
   nodes[i].scrollTop = 0;
 }
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-ref.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-ref.html
index 32bb610..911e7ac 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-ref.html
@@ -166,8 +166,8 @@
 }
 nodes = document.querySelectorAll(".rtl > .row-reverse");
 for (var i = 0; i < nodes.length; i++) {
-  nodes[i].scrollLeft = 0;
-  nodes[i].scrollTop = 0;
+  nodes[i].scrollLeft = -10000;
+  nodes[i].scrollTop = -10000;
 }
 nodes = document.querySelectorAll(".column-reverse");
 for (var i = 0; i < nodes.length; i++) {
@@ -176,7 +176,7 @@
 }
 nodes = document.querySelectorAll(".flipped-blocks > .column-reverse");
 for (var i = 0; i < nodes.length; i++) {
-  nodes[i].scrollLeft = 0;
+  nodes[i].scrollLeft = -10000;
   nodes[i].scrollTop = 0;
 }
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-sticky-writing-modes-ref.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-sticky-writing-modes-ref.html
index 3980086..b9771acf 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-position/position-sticky-writing-modes-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-sticky-writing-modes-ref.html
@@ -35,7 +35,7 @@
   document.getElementById('scroller1').scrollTop = 50;
   document.getElementById('scroller1').scrollLeft = 20;
   document.getElementById('scroller2').scrollTop = 50;
-  document.getElementById('scroller2').scrollLeft = 60;
+  document.getElementById('scroller2').scrollLeft = -25;
 });
 </script>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-sticky-writing-modes.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-sticky-writing-modes.html
index ee2dbc0..da27f50c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-position/position-sticky-writing-modes.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-sticky-writing-modes.html
@@ -44,7 +44,7 @@
   document.getElementById('scroller1').scrollTop = 50;
   document.getElementById('scroller1').scrollLeft = 20;
   document.getElementById('scroller2').scrollTop = 50;
-  document.getElementById('scroller2').scrollLeft = 60;
+  document.getElementById('scroller2').scrollLeft = -25;
 });
 </script>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/text-anchor-in-vertical-rl-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/text-anchor-in-vertical-rl-expected.txt
deleted file mode 100644
index f2c8c5ac..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/text-anchor-in-vertical-rl-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Line at edge of scrollport shouldn't jump visually when content is inserted before assert_equals: expected -400 but got 300
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block-expected.txt
index 4819c39..49f8a89 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 PASS Snaps correctly for horizontal-tb writing mode with 'scroll-snap-align: end start' alignment
 PASS Snaps correctly for vertical-lr writing mode with 'scroll-snap-align: end start' alignment
-FAIL Snaps correctly for vertical-rl writing mode with 'scroll-snap-align: end start' alignment assert_equals: aligns correctly on x expected -315 but got 300
-FAIL Snaps correctly for horizontal-tb writing mode with 'scroll-snap-align: start end' alignment assert_equals: aligns correctly on x expected 115 but got 0
-FAIL Snaps correctly for vertical-lr writing mode with 'scroll-snap-align: start end' alignment assert_equals: aligns correctly on x expected 300 but got 0
-FAIL Snaps correctly for vertical-rl writing mode with 'scroll-snap-align: start end' alignment assert_equals: aligns correctly on x expected -500 but got 115
-FAIL Snaps correctly for 'direction: rtl' with 'scroll-snap-align: end start' alignment assert_equals: aligns correctly on x expected -500 but got 0
-FAIL Snaps correctly for 'direction: rtl' with 'scroll-snap-align: start end' alignment assert_equals: aligns correctly on x expected -315 but got 0
+PASS Snaps correctly for vertical-rl writing mode with 'scroll-snap-align: end start' alignment
+PASS Snaps correctly for horizontal-tb writing mode with 'scroll-snap-align: start end' alignment
+PASS Snaps correctly for vertical-lr writing mode with 'scroll-snap-align: start end' alignment
+PASS Snaps correctly for vertical-rl writing mode with 'scroll-snap-align: start end' alignment
+FAIL Snaps correctly for 'direction: rtl' with 'scroll-snap-align: end start' alignment assert_equals: aligns correctly on x expected -500 but got -315
+FAIL Snaps correctly for 'direction: rtl' with 'scroll-snap-align: start end' alignment assert_equals: aligns correctly on x expected -315 but got -500
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-margin-001.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-margin-001.html
index 39dea7e..28eca1a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-margin-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-margin-001.html
@@ -10,10 +10,12 @@
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
         <script src="support/parsing-utils.js"></script>
+        <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
     </head>
     <body>
         <div id="log"></div>
         <script type="text/javascript">
+        setup({explicit_done: true});
         var shape_margin_valid_unit_tests = [];
         ParsingUtils.validUnits.forEach(function(unit) {
             test = "10"+unit;
@@ -25,10 +27,16 @@
             testCase["expected_computed"] = test;
             shape_margin_valid_unit_tests.push(testCase);
         });
+
         generate_tests( ParsingUtils.testShapeMarginInlineStyle,
                         ParsingUtils.buildTestCases(shape_margin_valid_unit_tests, "inline"), true);
-        generate_tests( ParsingUtils.testShapeMarginComputedStyle,
-                        ParsingUtils.buildTestCases(shape_margin_valid_unit_tests, "computed"), true);
+        ParsingUtils.setupFonts();
+        document.fonts.ready.then(()=> {
+            generate_tests( ParsingUtils.testShapeMarginComputedStyle,
+                            ParsingUtils.buildTestCases(shape_margin_valid_unit_tests, "computed"), true);
+            ParsingUtils.restoreFonts();
+            done();
+        });
         </script>
     </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-004.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-004.html
index 01f3fc1b..289861ee1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-004.html
@@ -13,14 +13,21 @@
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
         <script src="support/parsing-utils.js"></script>
+        <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
     </head>
     <body>
         <div id="log"></div>
         <script type="text/javascript">
+            setup({explicit_done: true});
             generate_tests( ParsingUtils.testInlineStyle,
                             ParsingUtils.buildPositionTests("circle", true, 'lengthUnit + inline', ParsingUtils.validUnits) );
-            generate_tests( ParsingUtils.testComputedStyle,
-                            ParsingUtils.buildPositionTests("circle", true, 'lengthUnit + computed', ParsingUtils.validUnits) );
+            ParsingUtils.setupFonts();
+            document.fonts.ready.then(()=> {
+                generate_tests( ParsingUtils.testComputedStyle,
+                                ParsingUtils.buildPositionTests("circle", true, 'lengthUnit + computed', ParsingUtils.validUnits) );
+                ParsingUtils.restoreFonts();
+                done();
+            });
         </script>
     </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-005.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-005.html
index 7d90318..46cae04 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-005.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-circle-005.html
@@ -12,12 +12,19 @@
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
         <script src="support/parsing-utils.js"></script>
+        <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
     </head>
     <body>
         <div id="log"></div>
         <script type="text/javascript">
+            setup({explicit_done: true});
             generate_tests(ParsingUtils.testInlineStyle, ParsingUtils.buildRadiiTests('circle', 'lengthUnit + inline', ParsingUtils.validUnits));
-            generate_tests(ParsingUtils.testComputedStyle, ParsingUtils.buildRadiiTests('circle', 'lengthUnit + computed', ParsingUtils.validUnits));
+            ParsingUtils.setupFonts();
+            document.fonts.ready.then(()=> {
+                generate_tests(ParsingUtils.testComputedStyle, ParsingUtils.buildRadiiTests('circle', 'lengthUnit + computed', ParsingUtils.validUnits));
+                ParsingUtils.restoreFonts();
+                done();
+            });
         </script>
     </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt
new file mode 100644
index 0000000..5e2a163
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Shape Outside Basic Shape Computed Font Relative Lengths Uncaught TypeError: ParsingUtils.setupFonts(...) is not a function
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-004.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-004.html
index 7617a34..1d4aa85a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-004.html
@@ -13,14 +13,21 @@
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
         <script src="support/parsing-utils.js"></script>
+        <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
     </head>
     <body>
         <div id="log"></div>
         <script type="text/javascript">
+            setup({explicit_done: true});
             generate_tests( ParsingUtils.testInlineStyle,
                             ParsingUtils.buildPositionTests("ellipse", true, 'lengthUnit + inline', ParsingUtils.validUnits) );
-            generate_tests( ParsingUtils.testComputedStyle,
-                            ParsingUtils.buildPositionTests("ellipse", true, 'lengthUnit + computed', ParsingUtils.validUnits) );
+            ParsingUtils.setupFonts();
+            document.fonts.ready.then(()=> {
+                generate_tests( ParsingUtils.testComputedStyle,
+                                ParsingUtils.buildPositionTests("ellipse", true, 'lengthUnit + computed', ParsingUtils.validUnits) );
+                ParsingUtils.restoreFonts();
+                done();
+            });
         </script>
     </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-005.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-005.html
index fe5af3b..5acb994 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-005.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-ellipse-005.html
@@ -12,12 +12,20 @@
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
         <script src="support/parsing-utils.js"></script>
+        <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
     </head>
     <body>
         <div id="log"></div>
         <script type="text/javascript">
+            setup({explicit_done: true});
             generate_tests(ParsingUtils.testInlineStyle, ParsingUtils.buildRadiiTests('ellipse', 'lengthUnit + inline', ParsingUtils.validUnits));
-            generate_tests(ParsingUtils.testComputedStyle, ParsingUtils.buildRadiiTests('ellipse', 'lengthUnit + computed', ParsingUtils.validUnits));
+            ParsingUtils.setupFonts();
+            document.fonts.ready.then(()=> {
+                generate_tests(ParsingUtils.testComputedStyle,
+                                ParsingUtils.buildRadiiTests('ellipse', 'lengthUnit + computed', ParsingUtils.validUnits));
+                ParsingUtils.restoreFonts();
+                done();
+            });
         </script>
     </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-003.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-003.html
index 9b42070..3ffc2af 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-003.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-inset-003.html
@@ -13,15 +13,22 @@
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
         <script src="support/parsing-utils.js"></script>
+        <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
     </head>
     <body>
         <div id="log"></div>
         <script type="text/javascript">
+           setup({explicit_done: true});
            ParsingUtils.validUnits.forEach(function(unit) {
                 generate_tests(ParsingUtils.testInlineStyle, ParsingUtils.generateInsetRoundCases(unit, 'inline'));
            });
-           ParsingUtils.validUnits.forEach(function(unit) {
-                generate_tests(ParsingUtils.testComputedStyle, ParsingUtils.generateInsetRoundCases(unit, 'computed'));
+           ParsingUtils.setupFonts();
+           document.fonts.ready.then(()=> {
+                ParsingUtils.validUnits.forEach(function(unit) {
+                    generate_tests(ParsingUtils.testComputedStyle, ParsingUtils.generateInsetRoundCases(unit, 'computed'));
+                });
+                ParsingUtils.restoreFonts();
+                done();
            });
         </script>
     </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-polygon-004.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-polygon-004.html
index c9623a2e..e9ecf2d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-polygon-004.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-polygon-004.html
@@ -13,10 +13,12 @@
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
         <script src="support/parsing-utils.js"></script>
+        <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
     </head>
     <body>
         <div id="log"></div>
         <script type="text/javascript">
+            setup({explicit_done: true});
             var arg_length_units_tests = [
                ['%', 'px', 'px'],
                ['px', '%', 'px'],
@@ -31,8 +33,13 @@
             ];
             generate_tests( ParsingUtils.testInlineStyle,
                             ParsingUtils.buildPolygonTests(arg_length_units_tests, 'inline') );
-            generate_tests( ParsingUtils.testComputedStyle,
-                            ParsingUtils.buildPolygonTests(arg_length_units_tests, 'computed') );
+            ParsingUtils.setupFonts();
+            document.fonts.ready.then(()=> {
+                generate_tests( ParsingUtils.testComputedStyle,
+                                ParsingUtils.buildPolygonTests(arg_length_units_tests, 'computed') );
+                ParsingUtils.restoreFonts();
+                done();
+            });
         </script>
     </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-arguments-000.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-arguments-000.html
index 02d5bc78..08d5d47 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-arguments-000.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-arguments-000.html
@@ -13,6 +13,7 @@
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
         <script src="support/parsing-utils.js"></script>
+        <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
     </head>
     <body>
         <div id="log"></div>
@@ -21,6 +22,7 @@
             // fixed units: cm, mm, in, px, pt, pc
             // percentage unit: %
             // zero length: 0
+            setup({explicit_done: true});
             var basic_shape_args_tests = [
                 {
                   "name": "0-valued",
@@ -53,10 +55,17 @@
                   "expected_computed": "polygon(1% 2%)"
                 }
             ];
+
             generate_tests( ParsingUtils.testInlineStyle,
                             ParsingUtils.buildTestCases(basic_shape_args_tests, "inline") );
-            generate_tests( ParsingUtils.testComputedStyle,
-                            ParsingUtils.buildTestCases(basic_shape_args_tests, "computed") );
+            ParsingUtils.setupFonts();
+            document.fonts.ready.then(()=> {
+                generate_tests( ParsingUtils.testComputedStyle,
+                                ParsingUtils.buildTestCases(basic_shape_args_tests, "computed") );
+                ParsingUtils.restoreFonts();
+                done();
+            });
+
         </script>
     </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/support/parsing-utils.js b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/support/parsing-utils.js
index 118a1145..abadbf70 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/support/parsing-utils.js
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/support/parsing-utils.js
@@ -446,31 +446,32 @@
     }
 }
 
-function setupFonts(func) {
-    return function () {
-        var fontProperties = {
-            'font-family': 'Ahem',
-            'font-size': '16px',
-            'line-height': '1'
-        };
-        var savedValues = { };
-        each(fontProperties, function (key, value) {
-            savedValues[key] = document.body.style.getPropertyValue(key);
-            document.body.style.setProperty(key, value);
-        });
-        try {
-            func.apply(this, arguments);
-        } finally {
-            each(savedValues, function (key, value) {
-                if (value) {
-                    document.body.style.setProperty(key, value);
-                }
-                else {
-                    document.body.style.removeProperty(key);
-                }
-            });
-        }
+/// For saving and restoring font properties
+var savedFontValues = { };
+
+function setupFonts() {
+    var fontProperties = {
+        'font-family': 'Ahem',
+        'font-size': '16px',
+        'line-height': '1'
     };
+    savedFontValues = { };
+    each(fontProperties, function (key, value) {
+        savedFontValues[key] = document.body.style.getPropertyValue(key);
+        document.body.style.setProperty(key, value);
+    });
+}
+
+function restoreFonts() {
+    each(savedFontValues, function (key, value) {
+        if (value) {
+            document.body.style.setProperty(key, value);
+        }
+        else {
+            document.body.style.removeProperty(key);
+        }
+    });
+    savedFontValues = { };
 }
 
 var validUnits = [
@@ -819,11 +820,11 @@
 
 return {
     testInlineStyle: testInlineStyle,
-    testComputedStyle: setupFonts(testComputedStyle),
+    testComputedStyle: testComputedStyle,
     testShapeMarginInlineStyle: testShapeMarginInlineStyle,
-    testShapeMarginComputedStyle: setupFonts(testShapeMarginComputedStyle),
+    testShapeMarginComputedStyle: testShapeMarginComputedStyle,
     testShapeThresholdInlineStyle: testShapeThresholdInlineStyle,
-    testShapeThresholdComputedStyle: setupFonts(testShapeThresholdComputedStyle),
+    testShapeThresholdComputedStyle: testShapeThresholdComputedStyle,
     buildTestCases: buildTestCases,
     buildRadiiTests: buildRadiiTests,
     buildPositionTests: buildPositionTests,
@@ -834,6 +835,7 @@
     validUnits: validUnits,
     calcTestValues: calcTestValues,
     roundResultStr: roundResultStr,
-    setupFonts: setupFonts
+    setupFonts: setupFonts,
+    restoreFonts: restoreFonts,
 }
 })();
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-horizontal-tb-writing-mode-and-rtl-direction-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-horizontal-tb-writing-mode-and-rtl-direction-expected.txt
deleted file mode 100644
index e6c667c5..0000000
--- a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-horizontal-tb-writing-mode-and-rtl-direction-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-This is a testharness.js-based test.
-FAIL scrollIntoView({"block":"start","inline":"start"}) assert_approx_equals: scrollX expected -200 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"start","inline":"center"}) assert_approx_equals: scrollX expected -157.5 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"start","inline":"end"}) assert_approx_equals: scrollX expected -115 +/- 0.5 but got 200
-FAIL scrollIntoView({"block":"center","inline":"start"}) assert_approx_equals: scrollX expected -200 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"center","inline":"center"}) assert_approx_equals: scrollX expected -157.5 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"center","inline":"end"}) assert_approx_equals: scrollX expected -115 +/- 0.5 but got 200
-FAIL scrollIntoView({"block":"end","inline":"start"}) assert_approx_equals: scrollX expected -200 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"end","inline":"center"}) assert_approx_equals: scrollX expected -157.5 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"end","inline":"end"}) assert_approx_equals: scrollX expected -115 +/- 0.5 but got 200
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-sideways-lr-writing-mode-and-rtl-direction-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-sideways-lr-writing-mode-and-rtl-direction-expected.txt
deleted file mode 100644
index 8ed2baa..0000000
--- a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-sideways-lr-writing-mode-and-rtl-direction-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-This is a testharness.js-based test.
-FAIL scrollIntoView({"block":"start","inline":"start"}) assert_approx_equals: scrollX expected 200 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"start","inline":"center"}) assert_approx_equals: scrollX expected 200 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"start","inline":"end"}) assert_approx_equals: scrollY expected 115 +/- 0.5 but got 200
-FAIL scrollIntoView({"block":"center","inline":"start"}) assert_approx_equals: scrollX expected 157.5 +/- 0.5 but got 115
-PASS scrollIntoView({"block":"center","inline":"center"})
-FAIL scrollIntoView({"block":"center","inline":"end"}) assert_approx_equals: scrollX expected 157.5 +/- 0.5 but got 200
-FAIL scrollIntoView({"block":"end","inline":"start"}) assert_approx_equals: scrollY expected 200 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"end","inline":"center"}) assert_approx_equals: scrollX expected 115 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"end","inline":"end"}) assert_approx_equals: scrollX expected 115 +/- 0.5 but got 200
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-sideways-rl-writing-mode-and-rtl-direction-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-sideways-rl-writing-mode-and-rtl-direction-expected.txt
deleted file mode 100644
index 410a175..0000000
--- a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-sideways-rl-writing-mode-and-rtl-direction-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-This is a testharness.js-based test.
-FAIL scrollIntoView({"block":"start","inline":"start"}) assert_approx_equals: scrollX expected -200 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"start","inline":"center"}) assert_approx_equals: scrollX expected -200 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"start","inline":"end"}) assert_approx_equals: scrollX expected -200 +/- 0.5 but got 200
-FAIL scrollIntoView({"block":"center","inline":"start"}) assert_approx_equals: scrollX expected -157.5 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"center","inline":"center"}) assert_approx_equals: scrollX expected -157.5 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"center","inline":"end"}) assert_approx_equals: scrollX expected -157.5 +/- 0.5 but got 200
-FAIL scrollIntoView({"block":"end","inline":"start"}) assert_approx_equals: scrollX expected -115 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"end","inline":"center"}) assert_approx_equals: scrollX expected -115 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"end","inline":"end"}) assert_approx_equals: scrollX expected -115 +/- 0.5 but got 200
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-vertical-lr-writing-mode-and-rtl-direction-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-vertical-lr-writing-mode-and-rtl-direction-expected.txt
deleted file mode 100644
index 9c4115c..0000000
--- a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-vertical-lr-writing-mode-and-rtl-direction-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-This is a testharness.js-based test.
-FAIL scrollIntoView({"block":"start","inline":"start"}) assert_approx_equals: scrollY expected -200 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"start","inline":"center"}) assert_approx_equals: scrollY expected -157.5 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"start","inline":"end"}) assert_approx_equals: scrollY expected -115 +/- 0.5 but got 200
-FAIL scrollIntoView({"block":"center","inline":"start"}) assert_approx_equals: scrollY expected -200 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"center","inline":"center"}) assert_approx_equals: scrollY expected -157.5 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"center","inline":"end"}) assert_approx_equals: scrollY expected -115 +/- 0.5 but got 200
-FAIL scrollIntoView({"block":"end","inline":"start"}) assert_approx_equals: scrollY expected -200 +/- 0.5 but got 115
-FAIL scrollIntoView({"block":"end","inline":"center"}) assert_approx_equals: scrollY expected -157.5 +/- 0.5 but got 157
-FAIL scrollIntoView({"block":"end","inline":"end"}) assert_approx_equals: scrollY expected -115 +/- 0.5 but got 200
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-vertical-rl-writing-mode.html b/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-vertical-rl-writing-mode.html
index cec27f4..dc5f3e2 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-vertical-rl-writing-mode.html
+++ b/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollIntoView-vertical-rl-writing-mode.html
@@ -92,20 +92,6 @@
   inlineEnd: ((2*box_height) - scroller_height) + scrollbar_width,
 };
 
-// As browsers differ in the meaning of scrollLeft when
-// in a right-to-left mode, we adjust the expectation
-// to match the semantics of scrollLeft.
-// In vertical-rl mode, the scroll x coordinate should be nonpositive per the the spec.
-// But some browsers is nonnegative, so we adjust the expectation.
-scroller.scrollLeft = -1000;
-if(scroller.scrollLeft === 0) {
-  expectedX = {
-    blockStart: ((2*box_width) - scroller_width) + scrollbar_width,
-    blockCenter: ((3*box_width - scroller_width)/2) + (scrollbar_width/2),
-    blockEnd: box_width,
-  };
-}
-
 [
   [{block: "start", inline: "start"}, expectedX.blockStart, expectedY.inlineStart],
   [{block: "start", inline: "center"}, expectedX.blockStart, expectedY.inlineCenter],
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollLeftTop-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollLeftTop-expected.txt
deleted file mode 100644
index a0ecd95..0000000
--- a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollLeftTop-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-PASS writing-mode:horizontal-tb; direction:ltr
-FAIL writing-mode:horizontal-tb; direction:rtl assert_approx_equals: initial scrollLeft expected 0 +/- 0.5 but got 165
-PASS writing-mode:vertical-lr; direction:ltr
-FAIL writing-mode:vertical-lr; direction:rtl assert_approx_equals: initial scrollTop expected 0 +/- 0.5 but got 315
-FAIL writing-mode:vertical-rl; direction:ltr assert_approx_equals: initial scrollLeft expected 0 +/- 0.5 but got 165
-FAIL writing-mode:vertical-rl; direction:rtl assert_approx_equals: initial scrollLeft expected 0 +/- 0.5 but got 165
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/hr-time/META.yml b/third_party/blink/web_tests/external/wpt/hr-time/META.yml
index 2be3549..779d5b4 100644
--- a/third_party/blink/web_tests/external/wpt/hr-time/META.yml
+++ b/third_party/blink/web_tests/external/wpt/hr-time/META.yml
@@ -2,4 +2,3 @@
 suggested_reviewers:
   - plehegar
   - igrigorik
-  - toddreifsteck
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/actions/__dir__.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/actions/__dir__.ini
deleted file mode 100644
index 2bac0b5..0000000
--- a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/actions/__dir__.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-disabled:
-  if product == "chrome" and os == "mac": https://bugs.chromium.org/p/chromedriver/issues/detail?id=3114
diff --git a/third_party/blink/web_tests/external/wpt/navigation-timing/META.yml b/third_party/blink/web_tests/external/wpt/navigation-timing/META.yml
index c09a6e0..bfb0e0f 100644
--- a/third_party/blink/web_tests/external/wpt/navigation-timing/META.yml
+++ b/third_party/blink/web_tests/external/wpt/navigation-timing/META.yml
@@ -2,5 +2,4 @@
 suggested_reviewers:
   - plehegar
   - igrigorik
-  - toddreifsteck
   - yoavweiss
diff --git a/third_party/blink/web_tests/external/wpt/page-visibility/META.yml b/third_party/blink/web_tests/external/wpt/page-visibility/META.yml
index 509936c..9b9aea8 100644
--- a/third_party/blink/web_tests/external/wpt/page-visibility/META.yml
+++ b/third_party/blink/web_tests/external/wpt/page-visibility/META.yml
@@ -2,4 +2,3 @@
 suggested_reviewers:
   - plehegar
   - igrigorik
-  - toddreifsteck
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/META.yml b/third_party/blink/web_tests/external/wpt/performance-timeline/META.yml
index 46f16ae5..89fae1d 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/META.yml
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/META.yml
@@ -2,4 +2,3 @@
 suggested_reviewers:
   - plehegar
   - igrigorik
-  - toddreifsteck
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/META.yml b/third_party/blink/web_tests/external/wpt/resource-timing/META.yml
index 76176970..662c42cb 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/META.yml
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/META.yml
@@ -3,5 +3,4 @@
   - plehegar
   - zqzhang
   - igrigorik
-  - toddreifsteck
   - yoavweiss
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/current-time-writing-modes.html b/third_party/blink/web_tests/external/wpt/scroll-animations/current-time-writing-modes.html
index 89b78fc..083c4cf 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/current-time-writing-modes.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/current-time-writing-modes.html
@@ -51,7 +51,7 @@
   // The offset in the inline/horizontal direction should be inverted. The
   // block/vertical direction should be unaffected.
   scroller.scrollTop = 50;
-  scroller.scrollLeft = 75;
+  scroller.scrollLeft = 75 - scrollerSize;
 
   assert_equals(blockScrollTimeline.currentTime, 50, 'Scrolled block timeline');
   assert_equals(
@@ -105,7 +105,7 @@
   // horizontal/vertical cases, horizontal starts on the right-hand-side and
   // vertical is normal.
   scroller.scrollTop = 50;
-  scroller.scrollLeft = 75;
+  scroller.scrollLeft = 75 - scrollerSize;
 
   assert_equals(
       blockScrollTimeline.currentTime, scrollerSize - 75,
@@ -207,36 +207,36 @@
   assert_equals(
       calcScrollTimeline.currentTime, null, 'Unscrolled calc-based timeline');
 
-  // With direction rtl offsets are inverted, such that scrollLeft ==
-  // scrollerSize is the 'zero' point for currentTime. However the
+  // With direction rtl offsets are inverted, such that scrollLeft == 0
+  // is the 'zero' point for currentTime. However the
   // startScrollOffset is an absolute distance along the offset, so doesn't
   // need adjusting.
 
   // Check the length-based ScrollTimeline.
-  scroller.scrollLeft = scrollerSize;
+  scroller.scrollLeft = 0;
   assert_equals(
       lengthScrollTimeline.currentTime, null,
       'Length-based timeline before the startScrollOffset point');
-  scroller.scrollLeft = scrollerSize - 20;
+  scroller.scrollLeft = -20;
   assert_equals(
       lengthScrollTimeline.currentTime, 0,
       'Length-based timeline at the startScrollOffset point');
-  scroller.scrollLeft = scrollerSize - 50;
+  scroller.scrollLeft = -50;
   assert_equals(
       lengthScrollTimeline.currentTime,
       calculateCurrentTime(50, 20, scrollerSize, scrollerSize),
       'Length-based timeline after the startScrollOffset point');
 
   // Check the percentage-based ScrollTimeline.
-  scroller.scrollLeft = scrollerSize - (0.19 * scrollerSize);
+  scroller.scrollLeft = -(0.19 * scrollerSize);
   assert_equals(
       percentageScrollTimeline.currentTime, null,
       'Percentage-based timeline before the startScrollOffset point');
-  scroller.scrollLeft = scrollerSize - (0.20 * scrollerSize);
+  scroller.scrollLeft = -(0.20 * scrollerSize);
   assert_equals(
       percentageScrollTimeline.currentTime, 0,
       'Percentage-based timeline at the startScrollOffset point');
-  scroller.scrollLeft = scrollerSize - (0.4 * scrollerSize);
+  scroller.scrollLeft = -(0.4 * scrollerSize);
   assert_equals(
       percentageScrollTimeline.currentTime,
       calculateCurrentTime(
@@ -244,15 +244,15 @@
       'Percentage-based timeline after the startScrollOffset point');
 
   // Check the calc-based ScrollTimeline.
-  scroller.scrollLeft = scrollerSize - (0.2 * scrollerSize - 10);
+  scroller.scrollLeft = -(0.2 * scrollerSize - 10);
   assert_equals(
       calcScrollTimeline.currentTime, null,
       'Calc-based timeline before the startScrollOffset point');
-  scroller.scrollLeft = scrollerSize - (0.2 * scrollerSize - 5);
+  scroller.scrollLeft = -(0.2 * scrollerSize - 5);
   assert_equals(
       calcScrollTimeline.currentTime, 0,
       'Calc-based timeline at the startScrollOffset point');
-  scroller.scrollLeft = scrollerSize - (0.2 * scrollerSize);
+  scroller.scrollLeft = -(0.2 * scrollerSize);
   assert_equals(
       calcScrollTimeline.currentTime,
       calculateCurrentTime(
@@ -288,21 +288,21 @@
     endScrollOffset: 'calc(80% + 5px)'
   });
 
-  // With direction rtl offsets are inverted, such that scrollLeft ==
-  // scrollerSize is the 'zero' point for currentTime. However the
+  // With direction rtl offsets are inverted, such that scrollLeft == 0
+  // is the 'zero' point for currentTime. However the
   // endScrollOffset is an absolute distance along the offset, so doesn't need
   // adjusting.
 
   // Check the length-based ScrollTimeline.
-  scroller.scrollLeft = 0;
+  scroller.scrollLeft = -scrollerSize;
   assert_equals(
       lengthScrollTimeline.currentTime, null,
       'Length-based timeline after the endScrollOffset point');
-  scroller.scrollLeft = 20;
+  scroller.scrollLeft = 20 - scrollerSize;
   assert_equals(
       lengthScrollTimeline.currentTime, null,
       'Length-based timeline at the endScrollOffset point');
-  scroller.scrollLeft = 50;
+  scroller.scrollLeft = 50 - scrollerSize;
   assert_equals(
       lengthScrollTimeline.currentTime,
       calculateCurrentTime(
@@ -310,15 +310,15 @@
       'Length-based timeline before the endScrollOffset point');
 
   // Check the percentage-based ScrollTimeline.
-  scroller.scrollLeft = 0.19 * scrollerSize;
+  scroller.scrollLeft = 0.19 * scrollerSize - scrollerSize;
   assert_equals(
       percentageScrollTimeline.currentTime, null,
       'Percentage-based timeline after the endScrollOffset point');
-  scroller.scrollLeft = 0.20 * scrollerSize;
+  scroller.scrollLeft = 0.20 * scrollerSize - scrollerSize;
   assert_equals(
       percentageScrollTimeline.currentTime, null,
       'Percentage-based timeline at the endScrollOffset point');
-  scroller.scrollLeft = 0.4 * scrollerSize;
+  scroller.scrollLeft = 0.4 * scrollerSize - scrollerSize;
   assert_equals(
       percentageScrollTimeline.currentTime,
       calculateCurrentTime(
@@ -326,15 +326,15 @@
       'Percentage-based timeline before the endScrollOffset point');
 
   // Check the calc-based ScrollTimeline. 80% + 5px
-  scroller.scrollLeft = 0.2 * scrollerSize - 10;
+  scroller.scrollLeft = -0.8 * scrollerSize - 10;
   assert_equals(
       calcScrollTimeline.currentTime, null,
       'Calc-based timeline after the endScrollOffset point');
-  scroller.scrollLeft = 0.2 * scrollerSize - 5;
+  scroller.scrollLeft = -0.8 * scrollerSize - 5;
   assert_equals(
       calcScrollTimeline.currentTime, null,
       'Calc-based timeline at the endScrollOffset point');
-  scroller.scrollLeft = 0.2 * scrollerSize;
+  scroller.scrollLeft = -0.8 * scrollerSize;
   assert_equals(
       calcScrollTimeline.currentTime,
       calculateCurrentTime(
diff --git a/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/META.yml b/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/META.yml
index c09a6e0..bfb0e0f 100644
--- a/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/META.yml
+++ b/third_party/blink/web_tests/external/wpt/timing-entrytypes-registry/META.yml
@@ -2,5 +2,4 @@
 suggested_reviewers:
   - plehegar
   - igrigorik
-  - toddreifsteck
   - yoavweiss
diff --git a/third_party/blink/web_tests/external/wpt/tools/ci/manifest_build.py b/third_party/blink/web_tests/external/wpt/tools/ci/manifest_build.py
index ade17d6..6400bfd5 100644
--- a/third_party/blink/web_tests/external/wpt/tools/ci/manifest_build.py
+++ b/third_party/blink/web_tests/external/wpt/tools/ci/manifest_build.py
@@ -43,7 +43,7 @@
         run(args + [path])
 
 
-def request(url, desc, data=None, json_data=None, params=None, headers=None):
+def request(url, desc, method=None, data=None, json_data=None, params=None, headers=None):
     github_token = os.environ.get("GITHUB_TOKEN")
     default_headers = {
         "Authorization": "token %s" % github_token,
@@ -57,12 +57,13 @@
     kwargs = {"params": params,
               "headers": _headers}
     try:
-        logger.info("Loading URL %s" % url)
+        logger.info("Requesting URL %s" % url)
         if json_data is not None or data is not None:
-            method = requests.post
+            if method is None:
+                method = requests.post
             kwargs["json"] = json_data
             kwargs["data"] = data
-        else:
+        elif method is None:
             method = requests.get
 
         resp = method(url, **kwargs)
@@ -105,32 +106,19 @@
     return pr["number"]
 
 
-def tag(owner, repo, sha, tag):
-    data = {"ref": "refs/tags/%s" % tag,
-            "sha": sha}
-    url = "https://api.github.com/repos/%s/%s/git/refs" % (owner, repo)
-
-    resp_data = request(url, "Tag creation", json_data=data)
-    if not resp_data:
-        return False
-
-    logger.info("Tagged %s as %s" % (sha, tag))
-    return True
-
-
 def create_release(manifest_path, owner, repo, sha, tag, body):
     create_url = "https://api.github.com/repos/%s/%s/releases" % (owner, repo)
     create_data = {"tag_name": tag,
+                   "target_commitish": sha,
                    "name": tag,
-                   "body": body}
-    create_data = request(create_url, "Release creation", json_data=create_data)
-    if not create_data:
+                   "body": body,
+                   "draft": True}
+    create_resp = request(create_url, "Release creation", json_data=create_data)
+    if not create_resp:
         return False
 
     # Upload URL contains '{?name,label}' at the end which we want to remove
-    upload_url = create_data["upload_url"].split("{", 1)[0]
-
-    success = True
+    upload_url = create_resp["upload_url"].split("{", 1)[0]
 
     upload_exts = [".gz", ".bz2", ".zst"]
     for upload_ext in upload_exts:
@@ -146,9 +134,17 @@
         upload_resp = request(upload_url, "Manifest upload", data=upload_data, params=params,
                               headers={'Content-Type': 'application/octet-stream'})
         if not upload_resp:
-            success = False
+            return False
 
-    return success
+    release_id = create_resp["id"]
+    edit_url = "https://api.github.com/repos/%s/%s/releases/%s" % (owner, repo, release_id)
+    edit_data = {"draft": False}
+    edit_resp = request(edit_url, "Release publishing", method=requests.patch, json_data=edit_data)
+    if not edit_resp:
+        return False
+
+    logger.info("Released %s" % edit_resp["html_url"])
+    return True
 
 
 def should_dry_run():
@@ -190,10 +186,6 @@
         return Status.FAIL
     tag_name = "merge_pr_%s" % pr
 
-    tagged = tag(owner, repo, head_rev, tag_name)
-    if not tagged:
-        return Status.FAIL
-
     if not create_release(manifest_path, owner, repo, head_rev, tag_name, body):
         return Status.FAIL
 
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/META.yml b/third_party/blink/web_tests/external/wpt/user-timing/META.yml
index a97a31d..5cb2a78 100644
--- a/third_party/blink/web_tests/external/wpt/user-timing/META.yml
+++ b/third_party/blink/web_tests/external/wpt/user-timing/META.yml
@@ -2,4 +2,3 @@
 suggested_reviewers:
   - plehegar
   - igrigorik
-  - toddreifsteck
diff --git a/third_party/blink/web_tests/external/wpt/web-share/share-sharePromise-internal-slot.https.html b/third_party/blink/web_tests/external/wpt/web-share/share-sharePromise-internal-slot.https.html
index 5a71eaa..1478158a 100644
--- a/third_party/blink/web_tests/external/wpt/web-share/share-sharePromise-internal-slot.https.html
+++ b/third_party/blink/web_tests/external/wpt/web-share/share-sharePromise-internal-slot.https.html
@@ -10,21 +10,27 @@
     <script src="/resources/testdriver-vendor.js"></script>
   </head>
   <body>
+    <button>
     <script>
+      setup({ allow_uncaught_exception:true });
       promise_test(async t => {
-        const [, promise2, promise3] = await test_driver.bless(
-          "share needs user activation",
-          () => {
-            return [
+        const button = document.querySelector("button");
+        const p = new Promise(r => {
+          button.onclick = () => {
+            const promises = [];
+            promises.push(
               navigator.share({ title: "should be pending" }),
               navigator.share({ title: "should reject" }),
-              navigator.share({ title: "should also reject" }),
-            ];
-          }
-        );
+              navigator.share({ title: "should also reject" })
+            );
+            r(promises);
+          };
+        });
+        test_driver.click(button);
+        const [, promise2, promise3] = await p;
         await Promise.all([
           promise_rejects(t, "InvalidStateError", promise2),
-          promise_rejects(t, "InvalidStateError", promise3),
+          promise_rejects(t, "InvalidStateError", promise3)
         ]);
       }, "Only allow one share call at a time, which is controlled by the [[sharePromise]] internal slot.");
     </script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrDevice_supportsSession_immersive.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrDevice_supportsSession_immersive.https.html
deleted file mode 100644
index fd0827a52..0000000
--- a/third_party/blink/web_tests/external/wpt/webxr/xrDevice_supportsSession_immersive.https.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<body>
-  <script src=/resources/testharness.js></script>
-  <script src=/resources/testharnessreport.js></script>
-  <script src="resources/webxr_util.js"></script>
-  <script src="resources/webxr_test_constants.js"></script>
-  <script>
-    xr_promise_test(
-      "supportsSession resolves when immersive options supported",
-      () => {
-        return navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE)
-          .then( (controller) => navigator.xr.supportsSession('immersive-vr'));
-      });
-  </script>
-</body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrDevice_supportsSession_immersive_unsupported.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrDevice_supportsSession_immersive_unsupported.https.html
deleted file mode 100644
index 1d63a2b..0000000
--- a/third_party/blink/web_tests/external/wpt/webxr/xrDevice_supportsSession_immersive_unsupported.https.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<body>
-  <script src=/resources/testharness.js></script>
-  <script src=/resources/testharnessreport.js></script>
-  <script src="resources/webxr_util.js"></script>
-  <script src="resources/webxr_test_constants.js"></script>
-  <script>
-    xr_promise_test(
-      "supportsSession rejects when options not supported",
-      (t) => {
-      return navigator.xr.test.simulateDeviceConnection(VALID_NON_IMMERSIVE_DEVICE)
-        .then( (controller) => {
-          return promise_rejects(
-            t,
-            "NotSupportedError",
-            navigator.xr.supportsSession('immersive-vr')
-          );
-        });
-    });
-  </script>
-</body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrDevice_supportsSession_non_immersive.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrDevice_supportsSession_non_immersive.https.html
deleted file mode 100644
index b376495..0000000
--- a/third_party/blink/web_tests/external/wpt/webxr/xrDevice_supportsSession_non_immersive.https.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<body>
-  <script src=/resources/testharness.js></script>
-  <script src=/resources/testharnessreport.js></script>
-  <script src="resources/webxr_util.js"></script>
-  <script src="resources/webxr_test_constants.js"></script>
-  <script>
-    xr_promise_test(
-      "supportsSession resolves when inline options supported",
-      (t) => {
-      return navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE)
-        .then( (controller) => {
-          // Inline sessions should be supported.
-          return navigator.xr.supportsSession('inline');
-        });
-    });
-  </script>
-</body>
diff --git a/third_party/blink/web_tests/fast/css/overflow-rtl-border-after.html b/third_party/blink/web_tests/fast/css/overflow-rtl-border-after.html
index 7f2066e2..b0652b25 100644
--- a/third_party/blink/web_tests/fast/css/overflow-rtl-border-after.html
+++ b/third_party/blink/web_tests/fast/css/overflow-rtl-border-after.html
@@ -16,7 +16,7 @@
     </style>
     <script src="../../resources/check-layout.js"></script>
   </head>
-  <body onload="checkLayout('#container'); container.scrollLeft = 1000;">
+  <body onload="checkLayout('#container'); container.scrollLeft = 0;">
     <!-- We have to set the scroll position, because of https://bugs.webkit.org/show_bug.cgi?id=76129
          Furthermore, inner.scrollIntoView() doesn't work, so just set some insane left value.
          This is just to make it look good; checkLayout() doesn't care. -->
diff --git a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-crash-expected.txt b/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-crash-expected.txt
deleted file mode 100644
index 41021419..0000000
--- a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-crash-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-CONSOLE MESSAGE: line 10: PASS unless crash.
- 
diff --git a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-crash.html b/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-crash.html
deleted file mode 100644
index 78e41261..0000000
--- a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-crash.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<iframe src=resources/append-child-adopt-node-frame.html></iframe>
-<iframe src=resources/append-child-adopt-node-frame.svg></iframe>
-<script>
-testRunner.waitUntilDone();
-testRunner.dumpAsText();
-
-// Don't use js-test.js because this bug is about <script> loading and
-// it makes sense to keep this small and easy to debug when regress.
-console.log("PASS unless crash.");
-
-var count = document.querySelectorAll("iframe").length;
-
-function done() {
-    if (--count)
-        return;
-    testRunner.notifyDone();
-}
-</script>
diff --git a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-error-crash-expected.txt b/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-error-crash-expected.txt
deleted file mode 100644
index 7e068f82..0000000
--- a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-error-crash-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-CONSOLE MESSAGE: line 9: PASS unless crash.
- 
diff --git a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-error-crash.html b/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-error-crash.html
deleted file mode 100644
index d1f4dd9..0000000
--- a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/append-child-adopt-node-error-crash.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<script>
-testRunner.waitUntilDone();
-testRunner.dumpAsText();
-
-// Don't use js-test.js because this bug is about a failing load of an async
-// <script> of a frame document being moved to its parent document.
-// Hence it makes sense to keep this small and easy to debug when regress.
-console.log("PASS unless crash.");
-
-var count = 2;
-
-function done() {
-    if (--count)
-        return;
-    testRunner.notifyDone();
-}
-</script>
-<iframe src=resources/append-child-adopt-node-error-frame.html></iframe>
-<iframe src=resources/append-child-adopt-node-error-frame.svg></iframe>
diff --git a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-error-frame.html b/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-error-frame.html
deleted file mode 100644
index 3095ba7..0000000
--- a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-error-frame.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<script>
-function init()
-{
-    var script = document.createElement("script");
-    script.src = "does-not-exist.js";
-    script.onerror = function () { window.top.done(); };
-    document.body.appendChild(script);
-    var contextDoc = window.top.document.implementation.createDocument("", null);
-    contextDoc.adoptNode(document.documentElement);
-}
-
-init();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-error-frame.svg b/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-error-frame.svg
deleted file mode 100644
index e3ab2f2..0000000
--- a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-error-frame.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
-<script>
-function init()
-{
-    var script = document.createElementNS("http://www.w3.org/2000/svg", "script");
-    script.setAttributeNS('http://www.w3.org/1999/xlink', 'href', "does-not-exist.js");
-
-    script.onerror = function() { window.top.done(); };
-    document.documentElement.appendChild(script);
-    var contextDoc = window.top.document.implementation.createDocument("", null);
-    contextDoc.adoptNode(document.documentElement);
-}
-init();
-</script>
-</svg>
diff --git a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-frame.html b/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-frame.html
deleted file mode 100644
index c150836..0000000
--- a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-frame.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<script>
-function init()
-{
-    var script = document.createElement("script");
-    script.src = "should-load.js";
-    document.body.appendChild(script);
-    var contextDoc = window.top.document.implementation.createDocument("", null);
-    contextDoc.adoptNode(document.documentElement);
-}
-
-init();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-frame.svg b/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-frame.svg
deleted file mode 100644
index a95608a6..0000000
--- a/third_party/blink/web_tests/fast/dom/HTMLScriptElement/resources/append-child-adopt-node-frame.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
-<script>
-function init()
-{
-    var script = document.createElementNS("http://www.w3.org/2000/svg", "script");
-    script.setAttributeNS('http://www.w3.org/1999/xlink', 'href', "should-load.js");
-    document.documentElement.appendChild(script);
-    var contextDoc = window.top.document.implementation.createDocument("", null);
-    contextDoc.adoptNode(document.documentElement);
-}
-init();
-</script>
-</svg>
diff --git a/third_party/blink/web_tests/fast/events/document-elementFromPoint.html b/third_party/blink/web_tests/fast/events/document-elementFromPoint.html
index c8b6bb0..f71e3f0 100644
--- a/third_party/blink/web_tests/fast/events/document-elementFromPoint.html
+++ b/third_party/blink/web_tests/fast/events/document-elementFromPoint.html
@@ -253,7 +253,7 @@
         // Scroll body and inner overflow box.
         window.scrollTo(20, 100);
         var overflowContent = document.getElementById('overflow');
-        overflowContent.scrollLeft = 80;
+        overflowContent.scrollLeft = 0;
         overflowContent.scrollTop = 60;
         setTimeout(function() {
             // Dispatch events.
diff --git a/third_party/blink/web_tests/fast/events/offsetX-offsetY.html b/third_party/blink/web_tests/fast/events/offsetX-offsetY.html
index d1bb965..03271261 100644
--- a/third_party/blink/web_tests/fast/events/offsetX-offsetY.html
+++ b/third_party/blink/web_tests/fast/events/offsetX-offsetY.html
@@ -20,15 +20,15 @@
       var resultsDiv = document.getElementById('results');
       resultsDiv.innerHTML += s + '<br>';
     }
-    
+
     function test()
     {
       // Scroll so that frame view offsets are non-zero
       window.scrollTo(20, 100);
 
-      document.getElementById('overflow').scrollLeft = 80;
+      document.getElementById('overflow').scrollLeft = 0;
       document.getElementById('overflow').scrollTop = 60;
-      
+
       // In non-test mode, show the mouse coords for testing
       if (!window.testRunner)
         document.body.addEventListener('mousemove', mousemoved, false);
@@ -95,7 +95,7 @@
       if (window.testRunner)
         testRunner.notifyDone();
     }
-    
+
     function sumPositions(element)
     {
         var offsetLeft = 0;
@@ -141,13 +141,13 @@
 
       log(result);
     }
-    
+
     window.addEventListener('load', function() {
       window.setTimeout(test, 0);
     }, false);
   </script>
   <style type="text/css" media="screen">
-  
+
     body {
       height: 2048px;
       width: 2048px;
@@ -170,7 +170,7 @@
       width: 200px;
       border: 15px solid gray;
     }
-    
+
     #rel-box {
       position: relative;
       height: 100px;
@@ -179,7 +179,7 @@
       top: -50px;
       background-color: #CCC;
     }
-    
+
     #fixed-box {
       position: fixed;
       top: 20px;
@@ -188,7 +188,7 @@
       height: 50px;
       background-color: #AAA;
     }
-    
+
     #columns {
       position: absolute;
       -webkit-column-count: 3;
@@ -197,7 +197,7 @@
       left: 460px;
       border: 2px solid black;
     }
-    
+
     #in-columns {
       display: block;
       height: 40px;
@@ -206,7 +206,7 @@
       text-align: center;
       background-color: gray;
     }
-    
+
     #transformed {
       height: 120px;
       width: 200px;
@@ -223,13 +223,13 @@
       border: 2px solid black;
       direction: rtl;
     }
-    
+
     #overflow-contents {
       height: 500px;
       width: 120%;
       background-color: #BBB;
     }
-    
+
     #inside-overflow {
       width: 50%;
       background-color: gray;
@@ -240,7 +240,7 @@
       left: 30px;
       top: 700px;
     }
-    
+
     #mousepos {
       position: absolute;
       left: 30px;
@@ -248,7 +248,7 @@
       color: gray;
       font-size: smaller;
     }
-    
+
     tr {
 /*      transform: rotate(10deg);*/
     }
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt
index f41dc78..d6e91002 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt
@@ -1,10 +1,10 @@
 This test verifies the hit test regions are updated correctly when composited layer are created and destroyed without triggering layout update during fast path animation.
 
-[object HTMLDivElement]: layer(0,0 800x600) has hit test rect (200,200 50x50)
+[object HTMLDivElement]: layer(800x600) has hit test rect (200,200 50x50)
 
-[object HTMLDivElement]: layer(200,200 50x50) has hit test rect (0,0 50x50)
+[object HTMLDivElement]: layer(50x50) has hit test rect (0,0 50x50)
 
-[object HTMLDivElement]: layer(0,0 800x600) has hit test rect (175,175 100x100)
+[object HTMLDivElement]: layer(800x600) has hit test rect (175,175 100x100)
 
 
 PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-global-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-global-expected.txt
index 7da5ff3..d60032f 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-global-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-global-expected.txt
@@ -1,11 +1,11 @@
 This tests verifies the hit test regions given to the compositor in the simple case where touch handles cover (or nearly cover) the entire document. It can only be run in DumpRenderTree.
 
-document: layer(0,0 800x600) has hit test rect (0,0 785x600)
-document: layer(0,0 785x2000) has hit test rect (0,0 785x2000)
+document: layer(800x600) has hit test rect (0,0 785x600)
+document: layer(785x2000) has hit test rect (0,0 785x2000)
 
-html: layer(0,0 785x2000) has hit test rect (0,0 785x2000)
+html: layer(785x2000) has hit test rect (0,0 785x2000)
 
-body: layer(0,0 785x2000) has hit test rect (5,16 775x1968)
+body: layer(785x2000) has hit test rect (5,16 775x1968)
 
 webPageOverlay: no rects
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-img-element-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-img-element-expected.txt
index 3de747e..68b1c558 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-img-element-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-img-element-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,8 13x13)
+: layer(800x600) has hit test rect (8,8 13x13)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-list-no-translate-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-list-no-translate-expected.txt
index 64fb3d8..7d4cee02 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-list-no-translate-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-list-no-translate-expected.txt
@@ -1,3 +1,3 @@
-list: layer(0,0 800x600) has hit test rect (13,10 290x14)
+list: layer(800x600) has hit test rect (13,10 290x14)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-many-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-many-expected.txt
index 43da10ac..6f6d6e6 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-many-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-many-expected.txt
@@ -5,107 +5,107 @@
 FAIL - got 101 rects, expected 1.
 Test node has 101 children with 102 rects
 FAIL - got 102 rects, expected 1.
-manychildren: layer(13,80 308x1228) has hit test rect (0,0 290x12)
-manychildren: layer(13,80 308x1228) has hit test rect (301,21 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,33 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,45 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,57 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,69 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,81 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,93 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,105 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,117 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,129 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,141 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,153 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,165 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,177 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,189 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,201 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,213 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,225 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,237 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,249 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,261 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,273 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,285 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,297 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,309 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,321 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,333 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,345 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,357 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,369 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,381 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,393 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,405 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,417 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,429 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,441 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,453 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,465 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,477 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,489 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,501 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,513 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,525 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,537 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,549 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,561 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,573 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,585 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,597 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,609 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,621 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,633 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,645 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,657 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,669 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,681 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,693 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,705 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,717 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,729 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,741 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,753 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,765 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,777 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,789 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,801 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,813 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,825 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,837 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,849 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,861 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,873 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,885 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,897 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,909 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,921 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,933 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,945 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,957 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,969 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,981 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,993 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1005 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1017 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1029 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1041 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1053 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1065 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1077 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1089 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1101 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1113 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1125 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1137 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1149 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1161 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1173 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1185 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1197 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1209 7x7)
-manychildren: layer(13,80 308x1228) has hit test rect (301,1221 7x7)
+manychildren: layer(308x1228) has hit test rect (0,0 290x12)
+manychildren: layer(308x1228) has hit test rect (301,21 7x7)
+manychildren: layer(308x1228) has hit test rect (301,33 7x7)
+manychildren: layer(308x1228) has hit test rect (301,45 7x7)
+manychildren: layer(308x1228) has hit test rect (301,57 7x7)
+manychildren: layer(308x1228) has hit test rect (301,69 7x7)
+manychildren: layer(308x1228) has hit test rect (301,81 7x7)
+manychildren: layer(308x1228) has hit test rect (301,93 7x7)
+manychildren: layer(308x1228) has hit test rect (301,105 7x7)
+manychildren: layer(308x1228) has hit test rect (301,117 7x7)
+manychildren: layer(308x1228) has hit test rect (301,129 7x7)
+manychildren: layer(308x1228) has hit test rect (301,141 7x7)
+manychildren: layer(308x1228) has hit test rect (301,153 7x7)
+manychildren: layer(308x1228) has hit test rect (301,165 7x7)
+manychildren: layer(308x1228) has hit test rect (301,177 7x7)
+manychildren: layer(308x1228) has hit test rect (301,189 7x7)
+manychildren: layer(308x1228) has hit test rect (301,201 7x7)
+manychildren: layer(308x1228) has hit test rect (301,213 7x7)
+manychildren: layer(308x1228) has hit test rect (301,225 7x7)
+manychildren: layer(308x1228) has hit test rect (301,237 7x7)
+manychildren: layer(308x1228) has hit test rect (301,249 7x7)
+manychildren: layer(308x1228) has hit test rect (301,261 7x7)
+manychildren: layer(308x1228) has hit test rect (301,273 7x7)
+manychildren: layer(308x1228) has hit test rect (301,285 7x7)
+manychildren: layer(308x1228) has hit test rect (301,297 7x7)
+manychildren: layer(308x1228) has hit test rect (301,309 7x7)
+manychildren: layer(308x1228) has hit test rect (301,321 7x7)
+manychildren: layer(308x1228) has hit test rect (301,333 7x7)
+manychildren: layer(308x1228) has hit test rect (301,345 7x7)
+manychildren: layer(308x1228) has hit test rect (301,357 7x7)
+manychildren: layer(308x1228) has hit test rect (301,369 7x7)
+manychildren: layer(308x1228) has hit test rect (301,381 7x7)
+manychildren: layer(308x1228) has hit test rect (301,393 7x7)
+manychildren: layer(308x1228) has hit test rect (301,405 7x7)
+manychildren: layer(308x1228) has hit test rect (301,417 7x7)
+manychildren: layer(308x1228) has hit test rect (301,429 7x7)
+manychildren: layer(308x1228) has hit test rect (301,441 7x7)
+manychildren: layer(308x1228) has hit test rect (301,453 7x7)
+manychildren: layer(308x1228) has hit test rect (301,465 7x7)
+manychildren: layer(308x1228) has hit test rect (301,477 7x7)
+manychildren: layer(308x1228) has hit test rect (301,489 7x7)
+manychildren: layer(308x1228) has hit test rect (301,501 7x7)
+manychildren: layer(308x1228) has hit test rect (301,513 7x7)
+manychildren: layer(308x1228) has hit test rect (301,525 7x7)
+manychildren: layer(308x1228) has hit test rect (301,537 7x7)
+manychildren: layer(308x1228) has hit test rect (301,549 7x7)
+manychildren: layer(308x1228) has hit test rect (301,561 7x7)
+manychildren: layer(308x1228) has hit test rect (301,573 7x7)
+manychildren: layer(308x1228) has hit test rect (301,585 7x7)
+manychildren: layer(308x1228) has hit test rect (301,597 7x7)
+manychildren: layer(308x1228) has hit test rect (301,609 7x7)
+manychildren: layer(308x1228) has hit test rect (301,621 7x7)
+manychildren: layer(308x1228) has hit test rect (301,633 7x7)
+manychildren: layer(308x1228) has hit test rect (301,645 7x7)
+manychildren: layer(308x1228) has hit test rect (301,657 7x7)
+manychildren: layer(308x1228) has hit test rect (301,669 7x7)
+manychildren: layer(308x1228) has hit test rect (301,681 7x7)
+manychildren: layer(308x1228) has hit test rect (301,693 7x7)
+manychildren: layer(308x1228) has hit test rect (301,705 7x7)
+manychildren: layer(308x1228) has hit test rect (301,717 7x7)
+manychildren: layer(308x1228) has hit test rect (301,729 7x7)
+manychildren: layer(308x1228) has hit test rect (301,741 7x7)
+manychildren: layer(308x1228) has hit test rect (301,753 7x7)
+manychildren: layer(308x1228) has hit test rect (301,765 7x7)
+manychildren: layer(308x1228) has hit test rect (301,777 7x7)
+manychildren: layer(308x1228) has hit test rect (301,789 7x7)
+manychildren: layer(308x1228) has hit test rect (301,801 7x7)
+manychildren: layer(308x1228) has hit test rect (301,813 7x7)
+manychildren: layer(308x1228) has hit test rect (301,825 7x7)
+manychildren: layer(308x1228) has hit test rect (301,837 7x7)
+manychildren: layer(308x1228) has hit test rect (301,849 7x7)
+manychildren: layer(308x1228) has hit test rect (301,861 7x7)
+manychildren: layer(308x1228) has hit test rect (301,873 7x7)
+manychildren: layer(308x1228) has hit test rect (301,885 7x7)
+manychildren: layer(308x1228) has hit test rect (301,897 7x7)
+manychildren: layer(308x1228) has hit test rect (301,909 7x7)
+manychildren: layer(308x1228) has hit test rect (301,921 7x7)
+manychildren: layer(308x1228) has hit test rect (301,933 7x7)
+manychildren: layer(308x1228) has hit test rect (301,945 7x7)
+manychildren: layer(308x1228) has hit test rect (301,957 7x7)
+manychildren: layer(308x1228) has hit test rect (301,969 7x7)
+manychildren: layer(308x1228) has hit test rect (301,981 7x7)
+manychildren: layer(308x1228) has hit test rect (301,993 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1005 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1017 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1029 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1041 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1053 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1065 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1077 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1089 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1101 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1113 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1125 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1137 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1149 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1161 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1173 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1185 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1197 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1209 7x7)
+manychildren: layer(308x1228) has hit test rect (301,1221 7x7)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt
index ce49af64..d18fb1f 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt
@@ -1,20 +1,20 @@
 This test verifies the hit test regions given to the compositor specifically around non-composited overflow scroll elements.
 
-scrollContent: layer(0,0 800x600) has hit test rect (14,63 273x12)
+scrollContent: layer(800x600) has hit test rect (14,63 273x12)
 
-scrollContainerWithHandler: layer(0,0 800x600) has hit test rect (13,89 290x32)
+scrollContainerWithHandler: layer(800x600) has hit test rect (13,89 290x32)
 
-nestedContent: layer(0,0 800x600) has hit test rect (15,148 256x9)
+nestedContent: layer(800x600) has hit test rect (15,148 256x9)
 
-fixedPositionContentContainer: layer(0,0 800x600) has hit test rect (14,179 273x12)
-fixedPositionContentContainer: layer(0,0 800x600) has hit test rect (310,190 132x12)
+fixedPositionContentContainer: layer(800x600) has hit test rect (14,179 273x12)
+fixedPositionContentContainer: layer(800x600) has hit test rect (310,190 132x12)
 
-overflowwithhandler: layer(0,0 785x623) has hit test rect (14,221 273x20)
+overflowwithhandler: layer(785x623) has hit test rect (14,221 273x20)
 
-divInsideNonScrollableLayer: layer(0,0 785x671) has hit test rect (14,273 273x10)
+divInsideNonScrollableLayer: layer(785x671) has hit test rect (14,273 273x10)
 
-divInsideCompositedLayer: layer(14,305 273x22) has hit test rect (0,10 273x12)
+divInsideCompositedLayer: layer(273x22) has hit test rect (0,10 273x12)
 
-overflowwithborder: layer(0,0 785x767) has hit test rect (13,336 290x50)
+overflowwithborder: layer(785x767) has hit test rect (13,336 290x50)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt
index 12bc184..1e40f42 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt
@@ -1,4 +1,4 @@
-notclipped: layer(0,0 800x600) has hit test rect (1,51 200x25)
+notclipped: layer(800x600) has hit test rect (1,51 200x25)
 
 clipped: no rects
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt
index fba4b10..47d35c3a 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt
@@ -1,20 +1,20 @@
 This test verifies the hit test regions given to the compositor specifically around composited overflow scroll elements.
 
-scrollContent: layer(0,0 273x75) has hit test rect (0,13 273x12)
+scrollContent: layer(273x75) has hit test rect (0,13 273x12)
 
-scrollContent5: layer(0,0 273x85) has hit test rect (0,13 273x12)
+scrollContent5: layer(273x85) has hit test rect (0,13 273x12)
 
-scrollContent6: layer(14,203 273x12) has hit test rect (0,0 273x12)
+scrollContent6: layer(273x12) has hit test rect (0,0 273x12)
 
-nestedContent: layer(0,0 256x72) has hit test rect (0,30 256x12)
+nestedContent: layer(256x72) has hit test rect (0,30 256x12)
 
-overflowwithhandler: layer(0,0 256x116) has hit test rect (0,0 256x116)
-overflowwithhandler: layer(0,10 273x52) has hit test rect (0,0 273x52)
+overflowwithhandler: layer(256x116) has hit test rect (0,0 256x116)
+overflowwithhandler: layer(273x52) has hit test rect (0,0 273x52)
 
-overflowwithborder: layer(13,365 290x70) has hit test rect (0,0 290x70)
-overflowwithborder: layer(0,0 263x124) has hit test rect (4,4 255x116)
+overflowwithborder: layer(290x70) has hit test rect (0,0 290x70)
+overflowwithborder: layer(263x124) has hit test rect (4,4 255x116)
 
-withTransform: layer(15,435 271x12) has hit test rect (0,0 271x12)
-withTransform: layer(0,0 282x77) has hit test rect (0,13 273x14)
+withTransform: layer(271x12) has hit test rect (0,0 271x12)
+withTransform: layer(282x77) has hit test rect (0,13 273x14)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-squashing-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-squashing-expected.txt
index bca5e9d..ac1239b 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-squashing-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-squashing-expected.txt
@@ -1,9 +1,9 @@
 This test verifies the hit test regions given to the compositor for composited layer squashing.
 
-behind: layer(65,95 52x52) has hit test rect (0,0 52x52)
+behind: layer(52x52) has hit test rect (0,0 52x52)
 
-middle: layer(25,55 132x132) has hit test rect (0,0 52x52)
+middle: layer(132x132) has hit test rect (0,0 52x52)
 
-top: layer(25,55 132x132) has hit test rect (80,80 52x52)
+top: layer(132x132) has hit test rect (80,80 52x52)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
index a554f6f2..125ebee 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,14 54x18)
+: layer(800x600) has hit test rect (8,14 54x18)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-expected.txt
index 2fe4e98..d210456 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-expected.txt
@@ -1,5 +1,5 @@
 This tests verifies the hit test regions given to the compositor for svg elements. It can only be run in DumpRenderTree.
 
-svgline: layer(0,0 800x600) has hit test rect (13,84 22x3)
+svgline: layer(800x600) has hit test rect (13,84 22x3)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-foreign-object-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-foreign-object-expected.txt
index 5cdc9c7..a311c26b 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-foreign-object-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-foreign-object-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,8 51x31)
+: layer(800x600) has hit test rect (8,8 51x31)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-image-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-image-expected.txt
index bab7649..42aec013 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-image-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-image-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,8 20x20)
+: layer(800x600) has hit test rect (8,8 20x20)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-root-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-root-expected.txt
index 050c10c..a870e08 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-root-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-root-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,8 53x54)
+: layer(800x600) has hit test rect (8,8 53x54)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
index a554f6f2..125ebee 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,14 54x18)
+: layer(800x600) has hit test rect (8,14 54x18)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-table-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-table-expected.txt
index 7922003..45050d4 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-table-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-table-expected.txt
@@ -1,7 +1,7 @@
-: layer(0,0 800x600) has hit test rect (8,8 116x20)
+: layer(800x600) has hit test rect (8,8 116x20)
 
-: layer(0,0 800x600) has hit test rect (8,30 114x14)
+: layer(800x600) has hit test rect (8,30 114x14)
 
-: layer(0,0 800x600) has hit test rect (10,48 54x14)
+: layer(800x600) has hit test rect (10,48 54x14)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout-expected.txt
index 58faa38..921ac73 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout-expected.txt
@@ -1,7 +1,7 @@
 This test verifies the touch event target rects are updated correctly when an element transfroms without causing layout.
 
-[object HTMLDivElement]: layer(0,0 800x600) has hit test rect (100,100 50x50)
+[object HTMLDivElement]: layer(800x600) has hit test rect (100,100 50x50)
 
-[object HTMLDivElement]: layer(0,0 800x600) has hit test rect (150,100 50x50)
+[object HTMLDivElement]: layer(800x600) has hit test rect (150,100 50x50)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-visibility-hidden-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-visibility-hidden-expected.txt
index 08ff1de..4892d6a 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-visibility-hidden-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-visibility-hidden-expected.txt
@@ -2,24 +2,24 @@
 
 : no rects
 
-: layer(0,0 785x1118) has hit test rect (13,220 42x42)
+: layer(785x1118) has hit test rect (13,220 42x42)
 
-: layer(0,0 785x1166) has hit test rect (13,325 102x102)
+: layer(785x1166) has hit test rect (13,325 102x102)
 
 : no rects
 
-: layer(0,0 785x1246) has hit test rect (8,532 100x100)
+: layer(785x1246) has hit test rect (8,532 100x100)
 
 : no rects
 
-: layer(0,0 785x1326) has hit test rect (8,738 100x100)
+: layer(785x1326) has hit test rect (8,738 100x100)
 
 : no rects
 
-: layer(0,0 785x1406) has hit test rect (120,840 102x102)
+: layer(785x1406) has hit test rect (120,840 102x102)
 
 : no rects
 
-: layer(0,0 785x1486) has hit test rect (118,944 100x100)
+: layer(785x1486) has hit test rect (118,944 100x100)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt
index d3c1fbe..7cb122b 100644
--- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt
+++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt
@@ -1,5 +1,5 @@
 This tests verifies the hit test regions given to the compositor for an element with child at negative offset. It can only be run in DumpRenderTree.
 
-negativeOffsetChild: layer(-96,96 211x13) has hit test rect (0,1 102x12)
+negativeOffsetChild: layer(211x13) has hit test rect (0,1 102x12)
 
 
diff --git a/third_party/blink/web_tests/fast/events/touch/resources/compositor-touch-hit-rects.js b/third_party/blink/web_tests/fast/events/touch/resources/compositor-touch-hit-rects.js
index 6f86cbb..38110e3f 100644
--- a/third_party/blink/web_tests/fast/events/touch/resources/compositor-touch-hit-rects.js
+++ b/third_party/blink/web_tests/fast/events/touch/resources/compositor-touch-hit-rects.js
@@ -61,7 +61,8 @@
     sortedRects.sort(sortRects);
     for ( var i = 0; i < sortedRects.length; ++i) {
         var rect = sortedRects[i].layerRect;
-        var rect_string = `${rect.x},${rect.y} ${rect.width}x${rect.height}`;
+        // Logging width/height for layer identification assistance.
+        var rect_string = `${rect.width}x${rect.height}`;
         var hit = sortedRects[i].hitTestRect;
         var hit_string = `${hit.x},${hit.y} ${hit.width}x${hit.height}`;
         log(`${testName}: layer(${rect_string}) has hit test rect (${hit_string})`);
diff --git a/third_party/blink/web_tests/fast/forms/textarea/textarea-selection-selectAll.html b/third_party/blink/web_tests/fast/forms/textarea/textarea-selection-selectAll.html
new file mode 100644
index 0000000..9478b5de
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/textarea/textarea-selection-selectAll.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>This test selectAll in textarea.</title>
+<link rel="author" title="yu.han" href="mailto:yuzhehan@chromium.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-textarea/input-setselectionrange">
+<script src=../../../resources/testharness.js></script>
+<script src=../../../resources/testharnessreport.js></script>
+<div id=log></div>
+<form id="form"><textarea id="form-textarea"></textarea></form>
+<script>
+test(function() {
+    var textarea = document.getElementById('form-textarea');
+    textarea.value = 'a\n';
+    textarea.focus();
+    document.execCommand('selectAll');
+    assert_equals(textarea.selectionStart, 0, 'textarea.selectionStart');
+    assert_equals(textarea.selectionEnd, 2, 'textarea.selectionEnd');
+}, 'textarea selection index is correct when text ends in newline');
+</script>
diff --git a/third_party/blink/web_tests/fast/overflow/overflow-rtl-vertical-origin.html b/third_party/blink/web_tests/fast/overflow/overflow-rtl-vertical-origin.html
index f9d2b79..963d125 100644
--- a/third_party/blink/web_tests/fast/overflow/overflow-rtl-vertical-origin.html
+++ b/third_party/blink/web_tests/fast/overflow/overflow-rtl-vertical-origin.html
@@ -4,7 +4,7 @@
         <div style="height: 300px; width: 100px;"></div>
     </div>
     <pre id="console"></pre>
-    
+
     <script>
         function log(msg)
         {
@@ -16,12 +16,12 @@
 
         var t = document.getElementById("test");
         var initialTop = t.scrollTop;
-        
-        // Scroll as far as you can.
-        t.scrollTop = 1000;
-        
+
+        // Scroll to the top edge.
+        t.scrollTop = 0;
+
         var newTop = t.scrollTop
-        
+
         if (initialTop == newTop)
             log("PASS: test.scrollTop is correct.")
         else
diff --git a/third_party/blink/web_tests/fast/overflow/rtl-scrollbar-drag-origin-expected.txt b/third_party/blink/web_tests/fast/overflow/rtl-scrollbar-drag-origin-expected.txt
index fab232a..7cac4da 100644
--- a/third_party/blink/web_tests/fast/overflow/rtl-scrollbar-drag-origin-expected.txt
+++ b/third_party/blink/web_tests/fast/overflow/rtl-scrollbar-drag-origin-expected.txt
@@ -1,5 +1,5 @@
-PASS container.scrollLeft is 0
-PASS container.scrollLeft is 350
+PASS container.scrollLeft is -715
+PASS container.scrollLeft is -365
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/blink/web_tests/fast/overflow/rtl-scrollbar-drag-origin.html b/third_party/blink/web_tests/fast/overflow/rtl-scrollbar-drag-origin.html
index c664eb5..c8087a7 100644
--- a/third_party/blink/web_tests/fast/overflow/rtl-scrollbar-drag-origin.html
+++ b/third_party/blink/web_tests/fast/overflow/rtl-scrollbar-drag-origin.html
@@ -25,7 +25,7 @@
 <script>
     window.jsTestIsAsync = true;
     var container = document.getElementById("container");
-    container.scrollLeft = 350;
+    container.scrollLeft = -365;
 
     if (window.eventSender) {
         eventSender.dragMode = false;
@@ -34,10 +34,10 @@
 
         eventSender.mouseMoveTo(100, 195);
         requestAnimationFrame(function() {
-            shouldBe("container.scrollLeft" , "0");
+            shouldBe("container.scrollLeft" , "-715");
             eventSender.mouseMoveTo(100, 700);
             requestAnimationFrame(function() {
-              shouldBe("container.scrollLeft" , "350");
+              shouldBe("container.scrollLeft" , "-365");
               finishJSTest();
             });
         });
diff --git a/third_party/blink/web_tests/fast/overflow/scroll-div-hide-show-expected.txt b/third_party/blink/web_tests/fast/overflow/scroll-div-hide-show-expected.txt
index 54bbdbd..659d5aa9 100644
--- a/third_party/blink/web_tests/fast/overflow/scroll-div-hide-show-expected.txt
+++ b/third_party/blink/web_tests/fast/overflow/scroll-div-hide-show-expected.txt
@@ -56,13 +56,13 @@
 
 
 Testing that scroll position is restored for RTL texts
-Scrolling to 50, 150
+Scrolling to -50, 150
 Div's display is none now
 PASS e.scrollTop is 0
 PASS e.scrollLeft is 0
 Div's display is block again
 PASS e.scrollTop is 150
-PASS e.scrollLeft is 50
+PASS e.scrollLeft is -50
 
 
 Test iframe scrolling
diff --git a/third_party/blink/web_tests/fast/overflow/scroll-div-hide-show.html b/third_party/blink/web_tests/fast/overflow/scroll-div-hide-show.html
index 198bf155..dfb4449 100644
--- a/third_party/blink/web_tests/fast/overflow/scroll-div-hide-show.html
+++ b/third_party/blink/web_tests/fast/overflow/scroll-div-hide-show.html
@@ -138,9 +138,9 @@
 
 e.dir="rtl";
 
-debug("Scrolling to 50, 150");
+debug("Scrolling to -50, 150");
 e.scrollTop = 150;
-e.scrollLeft = 50;
+e.scrollLeft = -50;
 debug("Div's display is none now");
 e.style.display = 'none';
 shouldBe('e.scrollTop', '0');
@@ -148,7 +148,7 @@
 debug("Div's display is block again");
 e.style.display = 'block';
 shouldBe('e.scrollTop', '150');
-shouldBe('e.scrollLeft', '50');
+shouldBe('e.scrollLeft', '-50');
 
 debug("");
 debug("Test iframe scrolling");
diff --git a/third_party/blink/web_tests/fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html b/third_party/blink/web_tests/fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html
index d301573..b2e0a3c 100644
--- a/third_party/blink/web_tests/fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html
+++ b/third_party/blink/web_tests/fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html
@@ -65,23 +65,23 @@
 
 promise_test (async () => {
   await mouseClickOn(510, 10);
-  scroller.scrollTo(0, 0);
+  scroller.scrollTo(-615, 0);
   await keyPress("ArrowRight");
   await waitForAnimationEnd(scrollLeft, 500, 15);
-  // The left border of #right is at 1000 - width.
-  // The right border of #right is thus 1200 - width.
-  // When right-aligned, the scroll position should be 1200 - 2 * width.
-  assert_equals(scroller.scrollLeft, 1200 - 2 * width);
+  // The left border of #right is at -width.
+  // The right border of #right is thus 200 - width.
+  // When right-aligned, the scroll position should be 200 - width.
+  assert_equals(scroller.scrollLeft, 200 - width);
 }, "Snaps to #right after pressing ArrowRight");
 
 promise_test (async () => {
   await mouseClickOn(510, 10);
-  scroller.scrollTo(400, 0);
+  scroller.scrollTo(-215, 0);
   await keyPress("ArrowLeft");
   await waitForAnimationEnd(scrollLeft, 500, 15);
-  // The left border of #left is at 600 - width.
-  // The right border of #left is thus 800 - width.
-  // When right-aligned, the scroll position should be 800 - 2 * width.
-  assert_equals(scroller.scrollLeft, 800 - 2 * width);
+  // The left border of #left is at -(400 + width).
+  // The right border of #left is thus -(200 + width).
+  // When right-aligned, the scroll position should be -(200 + width).
+  assert_equals(scroller.scrollLeft, -(200 + width));
 }, "Snaps to #left after pressing ArrowLeft");
 </script>
diff --git a/third_party/blink/web_tests/fast/scrolling/jquery-rtl-scroll-type.html b/third_party/blink/web_tests/fast/scrolling/jquery-rtl-scroll-type.html
index b230eba..587d64a 100644
--- a/third_party/blink/web_tests/fast/scrolling/jquery-rtl-scroll-type.html
+++ b/third_party/blink/web_tests/fast/scrolling/jquery-rtl-scroll-type.html
@@ -5,30 +5,30 @@
      to the right), some engines sets scrollLeft to 0 and decrement to negative
      values when scrolling leftwards (Gecko). Others set it to 0 and increment
      the value when scrolling leftwards (IE / Edge). Others again set it to the
-     width of the scrollable area and decrement it when scrolling leftwards
-     (Blink / WebKit). There are further complications in the latter engine if
+     width of the scrollable area and decrement it when scrolling leftwards.
+     WebKit / Blink used to be the third case, now they are consistent with Gecko.
+     There are further complications in the latter engine if
      there's a vertical scrollbar [1], and it's wider than the border box. All
      we need to worry about here though, is that the script is able to detect
-     that we are "default".
+     that we are "negative".
 
      [1] crbug.com/724255 -->
 <div id="definer" dir="rtl" style="font-size: 14px; width: 1px; height: 1px; position: absolute; top: -1000px; overflow: scroll">A</div>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script>
-    // This test is only expected to pass in Blink / WebKit.
     test(function() {
         var definer = document.getElementById('definer');
         var type = 'reverse';
-	if (definer.scrollLeft > 0) {
-	    type = 'default';
-	}
-	else {
-	    definer.scrollLeft = 1;
-	    if (definer.scrollLeft === 0) {
-		type = 'negative';
-	    }
-	}
-	assert_equals(type, 'default');
-    }, "Blink should have 'default' RTL scroll behavior");
+        if (definer.scrollLeft > 0) {
+            type = 'default';
+        }
+        else {
+            definer.scrollLeft = 1;
+            if (definer.scrollLeft === 0) {
+                type = 'negative';
+            }
+        }
+        assert_equals(type, 'negative');
+    }, "Blink should have 'negative' RTL scroll behavior");
 </script>
diff --git a/third_party/blink/web_tests/fast/scrolling/overflow-auto-ltr.html b/third_party/blink/web_tests/fast/scrolling/overflow-auto-ltr.html
index 5a0008d9..2519036 100644
--- a/third_party/blink/web_tests/fast/scrolling/overflow-auto-ltr.html
+++ b/third_party/blink/web_tests/fast/scrolling/overflow-auto-ltr.html
@@ -22,8 +22,8 @@
   description("Check that the scroll offset in an LTR block is correctly preserved when the existence of its vertical scrollbar changes.");
 
   var scrollLeftDiv = document.getElementById("scrollLeftRtl");
-  var initialOffset = scrollLeftDiv.scrollWidth - scrollLeftDiv.clientWidth - scrollLeftDiv.scrollLeft;
+  var initialOffset = scrollLeftDiv.scrollLeft;
   scrollLeftDiv.style.overflow = "auto";
-  var finalOffset = scrollLeftDiv.scrollWidth - scrollLeftDiv.clientWidth - scrollLeftDiv.scrollLeft;
+  var finalOffset = scrollLeftDiv.scrollLeft;
   shouldBe("finalOffset", "initialOffset");
 </script>
diff --git a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html
index 195453e..0f0c2ed 100644
--- a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html
+++ b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar.html
@@ -214,6 +214,64 @@
 
   promise_test (async () => {
     await waitForCompositorCommit();
+    resetScrollOffset(standardDivFast);
+
+    // Testing the vertical scrollbar thumb.
+    let x = standardRectFast.right - TRACK_WIDTH / 2;
+    let y = standardRectFast.top + BUTTON_WIDTH + 5;
+    let asc_increments = [15, 10, 7, 6, 2];
+    let asc_offsets = [343, 571, 732, 869, 915];
+    let desc_increments = [3, 2, 5, 9, 21];
+    let desc_offsets = [846, 800, 686, 480, 0];
+
+    await mouseMoveTo(x, y);
+    await mouseDownAt(x, y);
+
+    // Scroll down
+    for (var i = 0; i < 5; i++){
+      y += asc_increments[i];
+      await mouseMoveTo(x, y);
+      assert_equals(standardDivFast.scrollTop, asc_offsets[i], "Vertical thumb drag downwards did not scroll as expected at "+asc_increments[i]+" - ");
+    };
+
+    // Scroll up
+    for (var i = 0; i < 5; i++){
+      y -= desc_increments[i];
+      await mouseMoveTo(x, y);
+      assert_equals(standardDivFast.scrollTop, desc_offsets[i], "Vertical thumb drag upwards did not scroll as expected at "+desc_increments[i]+" - ");
+    };
+
+    await mouseUpAt(x, y);
+    assert_equals(standardDivFast.scrollTop, 0, "Mouseup on vertical scrollbar thumb is not expected to scroll.");
+
+    // Testing the horizontal scrollbar thumb.
+    resetScrollOffset(standardDivFast);
+    x = standardRectFast.left + BUTTON_WIDTH + 5;
+    y = standardRectFast.bottom - TRACK_WIDTH / 2;
+    await mouseMoveTo(x, y);
+    await mouseDownAt(x, y);
+
+    // Scroll right
+    for (var i = 0; i < 5; i++){
+      x += asc_increments[i];
+      await mouseMoveTo(x, y);
+      assert_equals(standardDivFast.scrollLeft, asc_offsets[i], "Horizontal thumb drag to the right did not scroll as expected at "+asc_increments[i]+" - ");
+    };
+
+    // Scroll left
+    for (var i = 0; i < 5; i++){
+      x -= desc_increments[i];
+      await mouseMoveTo(x, y);
+      assert_equals(standardDivFast.scrollLeft, desc_offsets[i], "Horizontal thumb drag to the left did not scroll as expected at "+desc_increments[i]+" - ");
+    };
+
+    await mouseUpAt(x, y);
+    assert_equals(standardDivFast.scrollLeft, 0,  "Mouseup on horizontal scrollbar thumb is not expected to scroll.");
+
+  }, "Test mouse drags in intervals on non-custom composited div scrollbar thumb.");
+
+  promise_test (async () => {
+    await waitForCompositorCommit();
     const customDivFast = document.getElementById("custom");
     const customRectFast = customDivFast.getBoundingClientRect();
 
diff --git a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html
index ea4b759..30cd01c 100644
--- a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html
+++ b/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-scrolling-on-root-scrollbar.html
@@ -127,6 +127,69 @@
     await mouseUpAt(x, y);
     assert_equals(window.scrollX, 0, "Mouseup on horizontal scrollbar thumb is not expected to scroll.");
   }, "Test mouse drags on non-custom composited root scrollbar thumb.");
+
+  promise_test (async () => {
+    await waitForCompositorCommit();
+    resetScrollOffset(document.scrollingElement);
+
+    // Testing the vertical scrollbar thumb.
+    let x = window.innerWidth - TRACK_WIDTH / 2;
+    let y = BUTTON_WIDTH + 10;
+    let asc_increments = [25, 10, 35, 7, 23];
+    let asc_offsets = [45, 64, 128, 141, 183];
+    let desc_increments = [33, 11, 21, 5, 30];
+    let desc_offsets = [122, 102, 64, 55, 0];
+
+    await mouseMoveTo(x, y);
+    await mouseDownAt(x, y);
+
+     // Scroll down
+    for (var i = 0; i < 5; i++){
+      y += asc_increments[i];
+      await mouseMoveTo(x, y);
+      assert_equals(window.scrollY, asc_offsets[i], "Vertical thumb drag downwards did not scroll as expected at "+asc_increments[i]+" - ");
+    };
+
+    // Scroll up
+    for (var i = 0; i < 5; i++){
+      y -= desc_increments[i];
+      await mouseMoveTo(x, y);
+      assert_equals(window.scrollY, desc_offsets[i], "Vertical thumb drag upwards did not scroll as expected at "+desc_increments[i]+" - ");
+    };
+
+    await mouseUpAt(x, y);
+    assert_equals(window.scrollY, 0, "Mouseup on vertical scrollbar thumb is not expected to scroll.");
+
+    // Testing the horizontal scrollbar thumb.
+    // TODO(sahir.vellani) test fails only on linux without resetScrollOffset,
+    // probably due to crbug.com/979408.
+    resetScrollOffset(document.scrollingElement);
+    x = BUTTON_WIDTH + 10;
+    y = window.innerHeight - TRACK_WIDTH / 2;
+    asc_offsets = [33, 46, 93, 102, 133];
+    desc_offsets = [89, 74, 46, 40, 0];
+
+    await mouseMoveTo(x, y);
+    await mouseDownAt(x, y);
+    assert_equals(window.scrollX, 0, "Mousedown on horizontal scrollbar thumb is not expected to scroll.");
+
+    // Scroll right
+    for (var i = 0; i < 5; i++){
+      x += asc_increments[i];
+      await mouseMoveTo(x, y);
+      assert_equals(window.scrollX, asc_offsets[i], "Horizontal thumb drag to the right did not scroll as expected at "+asc_increments[i]+" - ");
+    };
+
+    // Scroll left
+    for (var i = 0; i < 5; i++){
+      x -= desc_increments[i];
+      await mouseMoveTo(x, y);
+      assert_equals(window.scrollX, desc_offsets[i], "Horizontal thumb drag to the left did not scroll as expected at "+desc_increments[i]+" - ");
+    };
+
+    await mouseUpAt(x, y);
+    assert_equals(window.scrollX, 0, "Mouseup on horizontal scrollbar thumb is not expected to scroll.");
+  }, "Test mouse drags in increments on non-custom composited root scrollbar thumb.");
 }
 </script>
 </body>
diff --git a/third_party/blink/web_tests/fast/scrolling/scrollbars/scrollbar-thumb-snapping.html b/third_party/blink/web_tests/fast/scrolling/scrollbars/scrollbar-thumb-snapping.html
index edd98a1..4618a40a 100644
--- a/third_party/blink/web_tests/fast/scrolling/scrollbars/scrollbar-thumb-snapping.html
+++ b/third_party/blink/web_tests/fast/scrolling/scrollbars/scrollbar-thumb-snapping.html
@@ -51,9 +51,7 @@
 
     // Verify that scrolling occured.
     standardDivFast.addEventListener("scroll", function() {
-      // TODO(arakeri): There's a ~25px difference between main thread and cc thumb drags
-      // due to crbug.com/1009892. This needs to be changed to 480 once the crbug is fixed.
-      if(standardDivFast.scrollTop >= 450 && standardDivFast.scrollTop <= 480)
+      if(standardDivFast.scrollTop == 480)
         scroll_threshold_crossed = true;
     });
 
diff --git a/third_party/blink/web_tests/fast/writing-mode/flipped-block-with-local-background.html b/third_party/blink/web_tests/fast/writing-mode/flipped-block-with-local-background.html
index 79d41ef..b409a34d 100644
--- a/third_party/blink/web_tests/fast/writing-mode/flipped-block-with-local-background.html
+++ b/third_party/blink/web_tests/fast/writing-mode/flipped-block-with-local-background.html
@@ -18,5 +18,5 @@
   <div style="width:200px"></div>
 </div>
 <script>
-    document.getElementById('scroller').scrollLeft = 0;
+    document.getElementById('scroller').scrollLeft = -100;
 </script>
diff --git a/third_party/blink/web_tests/fast/writing-mode/flipped-blocks-hit-test-overflow-scroll.html b/third_party/blink/web_tests/fast/writing-mode/flipped-blocks-hit-test-overflow-scroll.html
index 5a6326f..269254d 100644
--- a/third_party/blink/web_tests/fast/writing-mode/flipped-blocks-hit-test-overflow-scroll.html
+++ b/third_party/blink/web_tests/fast/writing-mode/flipped-blocks-hit-test-overflow-scroll.html
@@ -13,7 +13,7 @@
         testRunner.dumpAsText();
 
     var scrollable = document.getElementById("scrollable");
-    scrollable.scrollLeft = 40;
+    scrollable.scrollLeft = -60;
     var target = document.getElementById("target");
     var hitContainer = document.caretRangeFromPoint(58, 100).startContainer;
     document.getElementById("result").innerText = hitContainer === target ? "PASS" : "FAIL";
diff --git a/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt b/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
index 5b45d439..071fa45 100644
--- a/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
@@ -1,7 +1,7 @@
 This tests verifies the hit test regions given to the compositor specifically for continuation case. It can only be run in DumpRenderTree.
 
-continuation: layer(0,0 800x600) has hit test rect (13,79 101x11)
-continuation: layer(0,0 800x600) has hit test rect (13,90 290x12)
-continuation: layer(0,0 800x600) has hit test rect (13,102 121x11)
+continuation: layer(800x600) has hit test rect (13,79 101x11)
+continuation: layer(800x600) has hit test rect (13,90 290x12)
+continuation: layer(800x600) has hit test rect (13,102 121x11)
 
 
diff --git a/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-expected.txt b/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-expected.txt
index 1eea2e4..c40a443 100644
--- a/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-expected.txt
@@ -1,49 +1,49 @@
 This tests verifies the hit test regions given to the compositor. It can only be run in DumpRenderTree. The outputted rects should cover the hit test regions of all the listed elements. Enable visualize mode to quickly validate graphically.
 
-normalFlow: layer(0,0 785x1530) has hit test rect (13,128 290x12)
+normalFlow: layer(785x1530) has hit test rect (13,128 290x12)
 
-inlineOverflow: layer(0,0 785x1578) has hit test rect (13,145 152x12)
-inlineOverflow: layer(0,0 785x1578) has hit test rect (13,157 42x10)
+inlineOverflow: layer(785x1578) has hit test rect (13,145 152x12)
+inlineOverflow: layer(785x1578) has hit test rect (13,157 42x10)
 
-absoluteChildContainer: layer(0,0 785x1658) has hit test rect (13,172 290x12)
-absoluteChildContainer: layer(0,0 785x1658) has hit test rect (320,173 142x12)
+absoluteChildContainer: layer(785x1658) has hit test rect (13,172 290x12)
+absoluteChildContainer: layer(785x1658) has hit test rect (320,173 142x12)
 
-relativeChildContainer: layer(0,0 785x1738) has hit test rect (13,189 290x22)
-relativeChildContainer: layer(0,0 785x1738) has hit test rect (314,199 142x12)
+relativeChildContainer: layer(785x1738) has hit test rect (13,189 290x22)
+relativeChildContainer: layer(785x1738) has hit test rect (314,199 142x12)
 
-fixed: layer(405,98 52x12) has hit test rect (0,0 52x12)
+fixed: layer(52x12) has hit test rect (0,0 52x12)
 
-translate: layer(0,0 785x1866) has hit test rect (13,216 290x14)
-translate: layer(0,0 785x1866) has hit test rect (314,219 288x12)
+translate: layer(785x1866) has hit test rect (13,216 290x14)
+translate: layer(785x1866) has hit test rect (314,219 288x12)
 
-transform2d: layer(0,0 785x1946) has hit test rect (16,236 284x20)
+transform2d: layer(785x1946) has hit test rect (16,236 284x20)
 
-overhangingContainer: layer(0,0 785x1994) has hit test rect (13,262 290x12)
-overhangingContainer: layer(0,0 785x1994) has hit test rect (14,274 102x10)
-overhangingContainer: layer(0,0 785x1994) has hit test rect (14,284 111x10)
-overhangingContainer: layer(0,0 785x1994) has hit test rect (14,294 102x11)
+overhangingContainer: layer(785x1994) has hit test rect (13,262 290x12)
+overhangingContainer: layer(785x1994) has hit test rect (14,274 102x10)
+overhangingContainer: layer(785x1994) has hit test rect (14,284 111x10)
+overhangingContainer: layer(785x1994) has hit test rect (14,294 102x11)
 
-transform3d: layer(14,316 288x12) has hit test rect (0,0 288x12)
-transform3d: layer(0,0 785x2138) has hit test rect (13,315 290x14)
+transform3d: layer(288x12) has hit test rect (0,0 288x12)
+transform3d: layer(785x2138) has hit test rect (13,315 290x14)
 
-negativeOffsetChild: layer(-96,339 211x13) has hit test rect (0,1 102x12)
+negativeOffsetChild: layer(211x13) has hit test rect (0,1 102x12)
 
-continuation: layer(0,0 785x2266) has hit test rect (13,355 101x11)
-continuation: layer(0,0 785x2266) has hit test rect (13,366 290x12)
-continuation: layer(0,0 785x2266) has hit test rect (13,378 121x11)
+continuation: layer(785x2266) has hit test rect (13,355 101x11)
+continuation: layer(785x2266) has hit test rect (13,366 290x12)
+continuation: layer(785x2266) has hit test rect (13,378 121x11)
 
-inlineAbsoluteChildContainer: layer(0,0 785x2378) has hit test rect (13,392 262x12)
-inlineAbsoluteChildContainer: layer(0,0 785x2378) has hit test rect (320,393 252x12)
+inlineAbsoluteChildContainer: layer(785x2378) has hit test rect (13,392 262x12)
+inlineAbsoluteChildContainer: layer(785x2378) has hit test rect (320,393 252x12)
 
-list: layer(0,0 785x2458) has hit test rect (13,413 290x14)
-list: layer(0,0 785x2458) has hit test rect (354,414 248x12)
+list: layer(785x2458) has hit test rect (13,413 290x14)
+list: layer(785x2458) has hit test rect (354,414 248x12)
 
-styleModified: layer(0,0 785x2548) has hit test rect (13,437 290x22)
+styleModified: layer(785x2548) has hit test rect (13,437 290x22)
 
-containsSvg: layer(0,0 785x2596) has hit test rect (13,464 290x16)
+containsSvg: layer(785x2596) has hit test rect (13,464 290x16)
 
-svgline: layer(0,0 785x2644) has hit test rect (13,489 22x3)
+svgline: layer(785x2644) has hit test rect (13,489 22x3)
 
-tablecell: layer(0,0 785x2692) has hit test rect (45,518 32x11)
+tablecell: layer(785x2692) has hit test rect (45,518 32x11)
 
 
diff --git a/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-list-translate-expected.txt b/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-list-translate-expected.txt
index e0c5934..9b2bb8a 100644
--- a/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-list-translate-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-blink-features=LayoutNG/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-list-translate-expected.txt
@@ -1,4 +1,4 @@
-list: layer(0,0 800x600) has hit test rect (13,10 290x14)
-list: layer(0,0 800x600) has hit test rect (354,11 248x12)
+list: layer(800x600) has hit test rect (13,10 290x14)
+list: layer(800x600) has hit test rect (354,11 248x12)
 
 
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt
index fb210c5..d6e91002 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt
@@ -1,10 +1,10 @@
 This test verifies the hit test regions are updated correctly when composited layer are created and destroyed without triggering layout update during fast path animation.
 
-[object HTMLDivElement]: layer(0,0 800x600) has hit test rect (200,200 50x50)
+[object HTMLDivElement]: layer(800x600) has hit test rect (200,200 50x50)
 
-[object HTMLDivElement]: layer(0,0 50x50) has hit test rect (0,0 50x50)
+[object HTMLDivElement]: layer(50x50) has hit test rect (0,0 50x50)
 
-[object HTMLDivElement]: layer(0,0 800x600) has hit test rect (175,175 100x100)
+[object HTMLDivElement]: layer(800x600) has hit test rect (175,175 100x100)
 
 
 PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt
index 558f8bdcd..862c037f 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt
@@ -1,4 +1,4 @@
-notclipped: layer(1,1 300x100) has hit test rect (0,50 200x25)
+notclipped: layer(300x100) has hit test rect (0,50 200x25)
 
 clipped: no rects
 
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt
index f7be972..11734996 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt
@@ -1,20 +1,20 @@
 This test verifies the hit test regions given to the compositor specifically around composited overflow scroll elements.
 
-scrollContent: layer(1,1 288x50) has hit test rect (0,0 273x10)
+scrollContent: layer(288x50) has hit test rect (0,0 273x10)
 
-scrollContent5: layer(1,1 288x50) has hit test rect (0,8 273x12)
+scrollContent5: layer(288x50) has hit test rect (0,8 273x12)
 
-scrollContent6: layer(0,0 785x601) has hit test rect (14,203 273x12)
+scrollContent6: layer(785x601) has hit test rect (14,203 273x12)
 
-nestedContent: layer(1,1 271x50) has hit test rect (0,12 256x12)
+nestedContent: layer(271x50) has hit test rect (0,12 256x12)
 
-overflowwithhandler: layer(1,1 271x50) has hit test rect (0,0 256x50)
-overflowwithhandler: layer(1,1 288x50) has hit test rect (0,10 273x40)
+overflowwithhandler: layer(271x50) has hit test rect (0,0 256x50)
+overflowwithhandler: layer(288x50) has hit test rect (0,10 273x40)
 
-overflowwithborder: layer(10,6 274x58) has hit test rect (0,0 255x58)
-overflowwithborder: layer(0,0 785x777) has hit test rect (13,365 290x70)
+overflowwithborder: layer(274x58) has hit test rect (0,0 255x58)
+overflowwithborder: layer(785x777) has hit test rect (13,365 290x70)
 
-withTransform: layer(12,25 271x12) has hit test rect (0,0 271x12)
-withTransform: layer(1,1 288x50) has hit test rect (0,0 273x7)
+withTransform: layer(271x12) has hit test rect (0,0 271x12)
+withTransform: layer(288x50) has hit test rect (0,0 273x7)
 
 
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt
index 84acd68..f3c5422 100644
--- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt
@@ -1,5 +1,5 @@
 This tests verifies the hit test regions given to the compositor for an element with child at negative offset. It can only be run in DumpRenderTree.
 
-negativeOffsetChild: layer(26,96 212x13) has hit test rect (0,1 103x12)
+negativeOffsetChild: layer(212x13) has hit test rect (0,1 103x12)
 
 
diff --git a/third_party/blink/web_tests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt b/third_party/blink/web_tests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
index fb7631e29..ce17ccb 100644
--- a/third_party/blink/web_tests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
+++ b/third_party/blink/web_tests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
@@ -1,14 +1,14 @@
 This test makes sure that touch hit rects are reported for fullscreen HTML5 video control elements even when there is a document handler.
 
 Should have single rect on document before fullscreen
-handler: layer(0,0 800x600) has hit test rect (0,0 800x600)
+handler: layer(800x600) has hit test rect (0,0 800x600)
 
 EVENT(webkitfullscreenchange)
 Should keep rect on document
-handler: layer(0,0 800x600) has hit test rect (0,0 800x600)
-handler: layer(0,0 800x600) has hit test rect (0,0 800x600)
-handler: layer(0,0 800x600) has hit test rect (0,0 800x600)
-handler: layer(0,0 800x600) has hit test rect (0,0 800x600)
+handler: layer(800x600) has hit test rect (0,0 800x600)
+handler: layer(800x600) has hit test rect (0,0 800x600)
+handler: layer(800x600) has hit test rect (0,0 800x600)
+handler: layer(800x600) has hit test rect (0,0 800x600)
 
 END OF TEST
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test-expected.txt b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test-expected.txt
new file mode 100644
index 0000000..a3e6814
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test-expected.txt
@@ -0,0 +1,7 @@
+Testing accessibility in the call stack sidebar pane.
+Set timer for test function.
+Call stack pane content: Show blackboxed framesNot paused(anonymous)test.js:20callWithAsyncStacktest.js:13call1wrapper.js:1Promise.then (async)callWithAsyncStacktest.js:17call2VM wrapper.js:1Promise.then (async)callWithAsyncStacktest.js:17call3VM wrapper.js:1Promise.then (async)callWithAsyncStacktest.js:17call4VM wrapper.js:1Promise.then (async)callWithAsyncStacktest.js:17call5VM wrapper.js:1Promise.then (async)callWithAsyncStacktest.js:17testFunctiontest.js:20setTimeout (async)scheduleTestFunctionVM:3(anonymous)VM:1Show more
+Running the axe-core linter on the call stack sidebar pane.
+aXe violations: []
+
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js
new file mode 100644
index 0000000..2f9a86b
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/a11y-axe-core/sources/call-stack-a11y-test.js
@@ -0,0 +1,37 @@
+// 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() {
+  await TestRunner.loadModule('axe_core_test_runner');
+  await TestRunner.loadModule('sources_test_runner');
+  await TestRunner.showPanel('sources');
+
+  TestRunner.addResult('Testing accessibility in the call stack sidebar pane.');
+  await TestRunner.evaluateInPagePromise(`
+      function callWithAsyncStack(f, depth) {
+        if (depth === 0) {
+          f();
+          return;
+        }
+        wrapper = eval('(function call' + depth + '() { callWithAsyncStack(f, depth - 1) }) //# sourceURL=wrapper.js');
+        Promise.resolve().then(wrapper);
+      }
+      function testFunction() {
+        callWithAsyncStack(() => {debugger}, 5);
+      }
+      //# sourceURL=test.js
+    `);
+
+  await SourcesTestRunner.startDebuggerTestPromise(/* quiet */ true);
+  await SourcesTestRunner.runTestFunctionAndWaitUntilPausedPromise();
+  await TestRunner.addSnifferPromise(
+      Sources.CallStackSidebarPane.prototype, '_updatedForTest');
+
+  const callStackPane = runtime.sharedInstance(Sources.CallStackSidebarPane);
+  const callStackElement = callStackPane.contentElement;
+  TestRunner.addResult(`Call stack pane content: ${TestRunner.clearSpecificInfoFromStackFrames(callStackElement.deepTextContent())}`);
+  TestRunner.addResult('Running the axe-core linter on the call stack sidebar pane.');
+  await AxeCoreTestRunner.runValidation(callStackElement);
+
+  TestRunner.completeTest();
+})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/webaudio/audio-context-selector-test-expected.txt b/third_party/blink/web_tests/http/tests/devtools/webaudio/audio-context-selector-test-expected.txt
new file mode 100644
index 0000000..1444f4e1
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/webaudio/audio-context-selector-test-expected.txt
@@ -0,0 +1,74 @@
+Tests the AudioContextSelector.
+
+Running: testStartsEmpty
+
+Number of contexts (items): 0
+Selected Context: null
+
+
+Running: testSelectsCreatedContext
+
+Number of contexts (items): 1
+Selected Context: {
+   "contextId": "924c4ee4-4cae-4e62-b4c6-71603edc39fd",
+   "contextType": "realtime"
+}
+
+
+Running: testResetClearsList
+
+Number of contexts (items): 0
+Selected Context: {
+   "contextId": "924c4ee4-4cae-4e62-b4c6-71603edc39fd",
+   "contextType": "realtime"
+}
+
+
+Running: testReSelectsCreatedContextAfterChange
+
+Number of contexts (items): 1
+Selected Context: {
+   "contextId": "924c4ee4-4cae-4e62-b4c6-71603edc39fd",
+   "contextType": "realtime"
+}
+
+
+Running: testFirstCreatedContextStaysSelected
+
+Number of contexts (items): 2
+Selected Context: {
+   "contextId": "924c4ee4-4cae-4e62-b4c6-71603edc39fd",
+   "contextType": "realtime"
+}
+
+
+Running: testChangingContextDoesNotChangeSelection
+
+Number of contexts (items): 2
+Selected Context: {
+   "contextId": "924c4ee4-4cae-4e62-b4c6-71603edc39fd",
+   "contextType": "realtime"
+}
+
+
+Running: testSelectedContextBecomesSelected
+
+Number of contexts (items): 2
+Selected Context: {
+   "contextId": "78a3e94e-4968-4bf6-8905-325109695c9e",
+   "contextType": "realtime"
+}
+
+
+Running: testOnListItemReplacedCalled
+_onListItemReplaced called with contexts (items) count: 1
+_onListItemReplaced called with contexts (items) count: 0
+_onListItemReplaced called with contexts (items) count: 1
+
+Number of contexts (items): 1
+Selected Context: {
+   "contextId": "924c4ee4-4cae-4e62-b4c6-71603edc39fd",
+   "contextType": "realtime"
+}
+
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/webaudio/audio-context-selector-test.js b/third_party/blink/web_tests/http/tests/devtools/webaudio/audio-context-selector-test.js
new file mode 100644
index 0000000..eae8a16
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/webaudio/audio-context-selector-test.js
@@ -0,0 +1,108 @@
+// 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 the AudioContextSelector.`);
+  await TestRunner.loadModule('web_audio');
+
+  /** @type {!Protocol.WebAudio.BaseAudioContext} */
+  const context1 = {
+    contextId: '924c4ee4-4cae-4e62-b4c6-71603edc39fd',
+    contextType: 'realtime'
+  };
+  /** @type {!Protocol.WebAudio.BaseAudioContext} */
+  const context2 = {
+    contextId: '78a3e94e-4968-4bf6-8905-325109695c9e',
+    contextType: 'realtime'
+  };
+
+  function dumpSelectorState(
+      /** @type {!WebAudio.AudioContextSelector} */ selector) {
+    TestRunner.addResult(`
+Number of contexts (items): ${selector._items.length}
+Selected Context: ${JSON.stringify(selector.selectedContext(), null, 3)}
+`);
+  }
+
+  TestRunner.runAsyncTestSuite([
+    async function testStartsEmpty() {
+      const selector = new WebAudio.AudioContextSelector();
+
+      dumpSelectorState(selector);
+    },
+
+    async function testSelectsCreatedContext() {
+      const selector = new WebAudio.AudioContextSelector();
+
+      selector.contextCreated({data: context1});
+
+      dumpSelectorState(selector);
+    },
+
+    async function testResetClearsList() {
+      const selector = new WebAudio.AudioContextSelector();
+
+      selector.contextCreated({data: context1});
+      selector.reset();
+
+      dumpSelectorState(selector);
+    },
+
+    async function testReSelectsCreatedContextAfterChange() {
+      const selector = new WebAudio.AudioContextSelector();
+
+      selector.contextCreated({data: context1});
+      selector.contextChanged({data: context1});
+
+      dumpSelectorState(selector);
+    },
+
+    async function testFirstCreatedContextStaysSelected() {
+      const selector = new WebAudio.AudioContextSelector();
+
+      selector.contextCreated({data: context1});
+      selector.contextCreated({data: context2});
+
+      dumpSelectorState(selector);
+    },
+
+    async function testChangingContextDoesNotChangeSelection() {
+      const selector = new WebAudio.AudioContextSelector();
+
+      selector.contextCreated({data: context1});
+      selector.contextCreated({data: context2});
+      selector.contextChanged({data: context2});
+
+      dumpSelectorState(selector);
+    },
+
+    async function testSelectedContextBecomesSelected() {
+      const selector = new WebAudio.AudioContextSelector();
+
+      selector.contextCreated({data: context1});
+      selector.contextCreated({data: context2});
+      selector.itemSelected(context2);
+
+      dumpSelectorState(selector);
+    },
+
+    async function testOnListItemReplacedCalled() {
+      function dumpItemCount() {
+        TestRunner.addResult(
+            `_onListItemReplaced called with contexts (items) count: ${
+                this._items.length}`);
+      }
+
+      TestRunner.addSniffer(
+          WebAudio.AudioContextSelector.prototype, '_onListItemReplaced',
+          dumpItemCount);
+
+      const selector = new WebAudio.AudioContextSelector();
+      selector.contextCreated({data: context1});
+      selector.contextChanged({data: context1});
+
+      dumpSelectorState(selector);
+    },
+  ]);
+})();
\ No newline at end of file
diff --git a/third_party/blink/web_tests/paint/invalidation/overflow/vertical-overflow-parent.html b/third_party/blink/web_tests/paint/invalidation/overflow/vertical-overflow-parent.html
index 2c3cf77..c8787c93 100644
--- a/third_party/blink/web_tests/paint/invalidation/overflow/vertical-overflow-parent.html
+++ b/third_party/blink/web_tests/paint/invalidation/overflow/vertical-overflow-parent.html
@@ -40,7 +40,7 @@
         };
         var container = document.getElementsByClassName("container")[0];
         runAfterLayoutAndPaint(function() {
-            container.scrollLeft = 0;
+            container.scrollLeft = -1815;
             runRepaintAndPixelTest();
         });
     </script>
diff --git a/third_party/blink/web_tests/paint/invalidation/overflow/vertical-overflow-same.html b/third_party/blink/web_tests/paint/invalidation/overflow/vertical-overflow-same.html
index d9d03e81..cbc94067 100644
--- a/third_party/blink/web_tests/paint/invalidation/overflow/vertical-overflow-same.html
+++ b/third_party/blink/web_tests/paint/invalidation/overflow/vertical-overflow-same.html
@@ -39,7 +39,7 @@
         };
         var container = document.getElementsByClassName("container")[0];
         runAfterLayoutAndPaint(function() {
-            container.scrollLeft = 0;
+            container.scrollLeft = -1815;
             runRepaintAndPixelTest();
         });
     </script>
diff --git a/third_party/blink/web_tests/paint/invalidation/scroll/flipped-blocks-writing-mode-scroll.html b/third_party/blink/web_tests/paint/invalidation/scroll/flipped-blocks-writing-mode-scroll.html
index 762412fd..1c64c3b 100644
--- a/third_party/blink/web_tests/paint/invalidation/scroll/flipped-blocks-writing-mode-scroll.html
+++ b/third_party/blink/web_tests/paint/invalidation/scroll/flipped-blocks-writing-mode-scroll.html
@@ -9,6 +9,6 @@
 onload = runRepaintAndPixelTest;
 function repaintTest() {
   target.style.background = "green";
-  scroller.scrollLeft = 0;
+  scroller.scrollLeft = -9600;
 }
 </script>
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt
deleted file mode 100644
index b54d554..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-PASS em units
-PASS ex units
-PASS ch units
-PASS rem units
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/linux/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt b/third_party/blink/web_tests/platform/linux/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
index 84adaf64..a177811 100644
--- a/third_party/blink/web_tests/platform/linux/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,13 54x19)
+: layer(800x600) has hit test rect (8,13 54x19)
 
 
diff --git a/third_party/blink/web_tests/platform/linux/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt b/third_party/blink/web_tests/platform/linux/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
index 84adaf64..a177811 100644
--- a/third_party/blink/web_tests/platform/linux/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,13 54x19)
+: layer(800x600) has hit test rect (8,13 54x19)
 
 
diff --git a/third_party/blink/web_tests/platform/linux/fast/overflow/rtl-scrollbar-drag-origin-expected.txt b/third_party/blink/web_tests/platform/linux/fast/overflow/rtl-scrollbar-drag-origin-expected.txt
deleted file mode 100644
index 3dd6d64..0000000
--- a/third_party/blink/web_tests/platform/linux/fast/overflow/rtl-scrollbar-drag-origin-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-PASS container.scrollLeft is 0
-FAIL container.scrollLeft should be 350. Was 0.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
-This test verifies scroll position restores correctly when a thumb drag has been cancelled in RTL mode.
-This test is expected to fail on Mac and Linux because those platforms don't cancel scrolling when mouse cursor is out of a certain range. It is Windows-specific behavior.
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
index 53e3325..bced82a 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
index 84adaf64..a177811 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,13 54x19)
+: layer(800x600) has hit test rect (8,13 54x19)
 
 
diff --git a/third_party/blink/web_tests/platform/linux/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
index 84adaf64..a177811 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,13 54x19)
+: layer(800x600) has hit test rect (8,13 54x19)
 
 
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
index 84adaf64..a177811 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,13 54x19)
+: layer(800x600) has hit test rect (8,13 54x19)
 
 
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
index 84adaf64..a177811 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,13 54x19)
+: layer(800x600) has hit test rect (8,13 54x19)
 
 
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
index 23f15ee..6aff6bd 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
index 23f15ee..6aff6bd 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
index 23f15ee..6aff6bd 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
index bd8db18..b1de4e47 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
@@ -1,5 +1,5 @@
 This tests verifies the hit test regions given to the compositor specifically for continuation case. It can only be run in DumpRenderTree.
 
-continuation: layer(0,0 800x600) has hit test rect (13,90 290x12)
+continuation: layer(800x600) has hit test rect (13,90 290x12)
 
 
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
index aed0054..fe48aae0 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt b/third_party/blink/web_tests/platform/mac-retina/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
index bd8db18..b1de4e47 100644
--- a/third_party/blink/web_tests/platform/mac-retina/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-retina/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
@@ -1,5 +1,5 @@
 This tests verifies the hit test regions given to the compositor specifically for continuation case. It can only be run in DumpRenderTree.
 
-continuation: layer(0,0 800x600) has hit test rect (13,90 290x12)
+continuation: layer(800x600) has hit test rect (13,90 290x12)
 
 
diff --git a/third_party/blink/web_tests/platform/mac/fast/overflow/rtl-scrollbar-drag-origin-expected.txt b/third_party/blink/web_tests/platform/mac/fast/overflow/rtl-scrollbar-drag-origin-expected.txt
deleted file mode 100644
index 3dd6d64..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/overflow/rtl-scrollbar-drag-origin-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-PASS container.scrollLeft is 0
-FAIL container.scrollLeft should be 350. Was 0.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
-This test verifies scroll position restores correctly when a thumb drag has been cancelled in RTL mode.
-This test is expected to fail on Mac and Linux because those platforms don't cancel scrolling when mouse cursor is out of a certain range. It is Windows-specific behavior.
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
index aed0054..fe48aae0 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt
deleted file mode 100644
index f94be57..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-shapes/shape-outside/values/shape-outside-computed-shape-000-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-PASS em units
-FAIL ex units assert_equals: expected "polygon(130.078px 130.078px)" but got "polygon(130.08px 130.08px)"
-PASS ch units
-PASS rem units
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt b/third_party/blink/web_tests/platform/win/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
index bd8db18..b1de4e47 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-continuation-expected.txt
@@ -1,5 +1,5 @@
 This tests verifies the hit test regions given to the compositor specifically for continuation case. It can only be run in DumpRenderTree.
 
-continuation: layer(0,0 800x600) has hit test rect (13,90 290x12)
+continuation: layer(800x600) has hit test rect (13,90 290x12)
 
 
diff --git a/third_party/blink/web_tests/scrollbars/rtl/div-horizontal-with-vertical-scrollbar.html b/third_party/blink/web_tests/scrollbars/rtl/div-horizontal-with-vertical-scrollbar.html
index 28748fd..fbf52d32 100644
--- a/third_party/blink/web_tests/scrollbars/rtl/div-horizontal-with-vertical-scrollbar.html
+++ b/third_party/blink/web_tests/scrollbars/rtl/div-horizontal-with-vertical-scrollbar.html
@@ -17,7 +17,7 @@
     var outerRTL = document.getElementById("outer-rtl");
     var innerRTL = document.getElementById("inner-rtl");
     outerLTR.scrollLeft = 0;
-    outerRTL.scrollLeft = 0;
+    outerRTL.scrollLeft = -10;
 
     // Verify the widths of the outer RTL elements are the same as the widths of the outer LTR elements.
     assert_equals(outerLTR.offsetWidth, outerRTL.offsetWidth);
diff --git a/third_party/blink/web_tests/scrollbars/rtl/div-horizontal.html b/third_party/blink/web_tests/scrollbars/rtl/div-horizontal.html
index 2837f7d..b63165d 100644
--- a/third_party/blink/web_tests/scrollbars/rtl/div-horizontal.html
+++ b/third_party/blink/web_tests/scrollbars/rtl/div-horizontal.html
@@ -16,7 +16,7 @@
     var outerRTL = document.getElementById("outer-rtl");
     var innerRTL = document.getElementById("inner-rtl");
     outerLTR.scrollLeft = 0;
-    outerRTL.scrollLeft = 0;
+    outerRTL.scrollLeft = -115;
 
     // Verify the widths of the outer RTL elements are the same as the widths of the outer LTR elements.
     assert_equals(outerLTR.offsetWidth, outerRTL.offsetWidth);
diff --git a/third_party/blink/web_tests/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png b/third_party/blink/web_tests/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
index f8a7012..121f14c 100644
--- a/third_party/blink/web_tests/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
+++ b/third_party/blink/web_tests/virtual/controls-refresh-high-contrast/fast/forms/controls-new-ui-high-contrast/color-picker-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt b/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
index a554f6f2..125ebee 100644
--- a/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
+++ b/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,14 54x18)
+: layer(800x600) has hit test rect (8,14 54x18)
 
 
diff --git a/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt b/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
index a554f6f2..125ebee 100644
--- a/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
+++ b/third_party/blink/web_tests/virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,14 54x18)
+: layer(800x600) has hit test rect (8,14 54x18)
 
 
diff --git a/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-expected.txt b/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-expected.txt
index bf3c3e6..e6b60e7 100644
--- a/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-expected.txt
+++ b/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-expected.txt
@@ -1,49 +1,49 @@
 This tests verifies the hit test regions given to the compositor. It can only be run in DumpRenderTree. The outputted rects should cover the hit test regions of all the listed elements. Enable visualize mode to quickly validate graphically.
 
-normalFlow: layer(0,0 785x1530) has hit test rect (13,128 290x12)
+normalFlow: layer(785x1530) has hit test rect (13,128 290x12)
 
-inlineOverflow: layer(0,0 785x1578) has hit test rect (13,145 17x1)
-inlineOverflow: layer(0,0 785x1578) has hit test rect (13,146 152x10)
-inlineOverflow: layer(0,0 785x1578) has hit test rect (13,156 42x10)
-inlineOverflow: layer(0,0 785x1578) has hit test rect (13,166 17x1)
+inlineOverflow: layer(785x1578) has hit test rect (13,145 17x1)
+inlineOverflow: layer(785x1578) has hit test rect (13,146 152x10)
+inlineOverflow: layer(785x1578) has hit test rect (13,156 42x10)
+inlineOverflow: layer(785x1578) has hit test rect (13,166 17x1)
 
-absoluteChildContainer: layer(0,0 785x1722) has hit test rect (13,172 290x12)
-absoluteChildContainer: layer(0,0 785x1722) has hit test rect (320,173 142x12)
+absoluteChildContainer: layer(785x1722) has hit test rect (13,172 290x12)
+absoluteChildContainer: layer(785x1722) has hit test rect (320,173 142x12)
 
-relativeChildContainer: layer(0,0 785x1802) has hit test rect (13,189 290x22)
-relativeChildContainer: layer(0,0 785x1802) has hit test rect (314,199 142x12)
+relativeChildContainer: layer(785x1802) has hit test rect (13,189 290x22)
+relativeChildContainer: layer(785x1802) has hit test rect (314,199 142x12)
 
-fixed: layer(405,98 52x12) has hit test rect (0,0 52x12)
+fixed: layer(52x12) has hit test rect (0,0 52x12)
 
-translate: layer(0,0 785x1930) has hit test rect (13,216 290x14)
-translate: layer(0,0 785x1930) has hit test rect (314,219 288x12)
+translate: layer(785x1930) has hit test rect (13,216 290x14)
+translate: layer(785x1930) has hit test rect (314,219 288x12)
 
-transform2d: layer(0,0 785x2010) has hit test rect (16,236 284x20)
+transform2d: layer(785x2010) has hit test rect (16,236 284x20)
 
-overhangingContainer: layer(0,0 785x2058) has hit test rect (13,262 290x12)
-overhangingContainer: layer(0,0 785x2058) has hit test rect (14,274 102x10)
-overhangingContainer: layer(0,0 785x2058) has hit test rect (14,284 111x10)
-overhangingContainer: layer(0,0 785x2058) has hit test rect (14,294 102x11)
+overhangingContainer: layer(785x2058) has hit test rect (13,262 290x12)
+overhangingContainer: layer(785x2058) has hit test rect (14,274 102x10)
+overhangingContainer: layer(785x2058) has hit test rect (14,284 111x10)
+overhangingContainer: layer(785x2058) has hit test rect (14,294 102x11)
 
-transform3d: layer(14,316 288x12) has hit test rect (0,0 288x12)
-transform3d: layer(0,0 785x2202) has hit test rect (13,315 290x14)
+transform3d: layer(288x12) has hit test rect (0,0 288x12)
+transform3d: layer(785x2202) has hit test rect (13,315 290x14)
 
-negativeOffsetChild: layer(-96,339 211x13) has hit test rect (0,1 102x12)
+negativeOffsetChild: layer(211x13) has hit test rect (0,1 102x12)
 
-continuation: layer(0,0 785x2330) has hit test rect (13,366 290x12)
+continuation: layer(785x2330) has hit test rect (13,366 290x12)
 
-inlineAbsoluteChildContainer: layer(0,0 785x2378) has hit test rect (320,393 252x12)
+inlineAbsoluteChildContainer: layer(785x2378) has hit test rect (320,393 252x12)
 
-list: layer(0,0 785x2426) has hit test rect (13,413 290x14)
-list: layer(0,0 785x2426) has hit test rect (354,414 248x12)
-list: layer(0,0 785x2426) has hit test rect (341,415 5x10)
+list: layer(785x2426) has hit test rect (13,413 290x14)
+list: layer(785x2426) has hit test rect (354,414 248x12)
+list: layer(785x2426) has hit test rect (341,415 5x10)
 
-styleModified: layer(0,0 785x2548) has hit test rect (13,437 290x22)
+styleModified: layer(785x2548) has hit test rect (13,437 290x22)
 
-containsSvg: layer(0,0 785x2596) has hit test rect (13,464 290x16)
+containsSvg: layer(785x2596) has hit test rect (13,464 290x16)
 
-svgline: layer(0,0 785x2644) has hit test rect (13,489 22x3)
+svgline: layer(785x2644) has hit test rect (13,489 22x3)
 
-tablecell: layer(0,0 785x2692) has hit test rect (45,518 32x11)
+tablecell: layer(785x2692) has hit test rect (45,518 32x11)
 
 
diff --git a/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-list-translate-expected.txt b/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-list-translate-expected.txt
index 933bb21..0582458 100644
--- a/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-list-translate-expected.txt
+++ b/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-list-translate-expected.txt
@@ -1,5 +1,5 @@
-list: layer(0,0 800x600) has hit test rect (13,10 290x14)
-list: layer(0,0 800x600) has hit test rect (354,11 248x12)
-list: layer(0,0 800x600) has hit test rect (341,12 5x10)
+list: layer(800x600) has hit test rect (13,10 290x14)
+list: layer(800x600) has hit test rect (354,11 248x12)
+list: layer(800x600) has hit test rect (341,12 5x10)
 
 
diff --git a/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt b/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
index a554f6f2..125ebee 100644
--- a/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
+++ b/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-container-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,14 54x18)
+: layer(800x600) has hit test rect (8,14 54x18)
 
 
diff --git a/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt b/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
index a554f6f2..125ebee 100644
--- a/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
+++ b/third_party/blink/web_tests/virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-svg-text-expected.txt
@@ -1,3 +1,3 @@
-: layer(0,0 800x600) has hit test rect (8,14 54x18)
+: layer(800x600) has hit test rect (8,14 54x18)
 
 
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/resources/xr-internal-device-mocking.js b/third_party/blink/web_tests/wpt_internal/webxr/resources/xr-internal-device-mocking.js
index 6be8bfa..191cb52 100644
--- a/third_party/blink/web_tests/wpt_internal/webxr/resources/xr-internal-device-mocking.js
+++ b/third_party/blink/web_tests/wpt_internal/webxr/resources/xr-internal-device-mocking.js
@@ -41,3 +41,21 @@
 // Patch in experimental features.
 MockRuntime.featureToMojoMap["dom-overlay-for-handheld-ar"] =
     device.mojom.XRSessionFeature.DOM_OVERLAY_FOR_HANDHELD_AR;
+
+ChromeXRTest.prototype.getService = function() {
+  return this.mockVRService_;
+}
+
+MockVRService.prototype.setFramesThrottled = function(throttled) {
+  return this.frames_throttled_ = throttled;
+}
+
+MockVRService.prototype.getFramesThrottled = function() {
+  // Explicitly converted falsey states (i.e. undefined) to false.
+  if (!this.frames_throttled_) {
+    return false;
+  }
+
+  return this.frames_throttled_;
+};
+
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/xrDevice_supportsSession_immersive.https.html b/third_party/blink/web_tests/wpt_internal/webxr/xrDevice_supportsSession_immersive.https.html
new file mode 100644
index 0000000..536088d
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webxr/xrDevice_supportsSession_immersive.https.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<body>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/webxr/resources/webxr_util.js"></script>
+  <script src="/webxr/resources/webxr_test_constants.js"></script>
+  <script>
+    // This test is chromium specific as though supportsSession is removed from
+    // the spec it is still implemented, albeit as a deprecated method, in
+    // chromium. Keeping this test until such time as it is removed.
+    xr_promise_test(
+      "supportsSession resolves when immersive options supported",
+      () => {
+        return navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE)
+          .then( (controller) => navigator.xr.supportsSession('immersive-vr'));
+      });
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/xrDevice_supportsSession_immersive_unsupported.https.html b/third_party/blink/web_tests/wpt_internal/webxr/xrDevice_supportsSession_immersive_unsupported.https.html
new file mode 100644
index 0000000..caa9c23
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webxr/xrDevice_supportsSession_immersive_unsupported.https.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<body>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/webxr/resources/webxr_util.js"></script>
+  <script src="/webxr/resources/webxr_test_constants.js"></script>
+  <script>
+    // This test is chromium specific as though supportsSession is removed from
+    // the spec it is still implemented, albeit as a deprecated method, in
+    // chromium. Keeping this test until such time as it is removed.
+    xr_promise_test(
+      "supportsSession rejects when options not supported",
+      (t) => {
+      return navigator.xr.test.simulateDeviceConnection(VALID_NON_IMMERSIVE_DEVICE)
+        .then( (controller) => {
+          return promise_rejects(
+            t,
+            "NotSupportedError",
+            navigator.xr.supportsSession('immersive-vr')
+          );
+        });
+    });
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/xrDevice_supportsSession_non_immersive.https.html b/third_party/blink/web_tests/wpt_internal/webxr/xrDevice_supportsSession_non_immersive.https.html
new file mode 100644
index 0000000..90276fe1
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webxr/xrDevice_supportsSession_non_immersive.https.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<body>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/webxr/resources/webxr_util.js"></script>
+  <script src="/webxr/resources/webxr_test_constants.js"></script>
+  <script>
+    // This test is chromium specific as, though supportsSession is removed from
+    // the spec it is still implemented, albeit as a deprecated method, in
+    // chromium. Keeping this test until such time as it is removed.
+    xr_promise_test(
+      "supportsSession resolves when inline options supported",
+      (t) => {
+      return navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE)
+        .then( (controller) => {
+          // Inline sessions should be supported.
+          return navigator.xr.supportsSession('inline');
+        });
+    });
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/xrSession_framesThrottled.https.html b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_framesThrottled.https.html
new file mode 100644
index 0000000..cab8378
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_framesThrottled.https.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>let additionalChromiumResources = ["resources/xr-internal-device-mocking.js"];</script>
+<script src="/webxr/resources/webxr_util.js"></script>
+<script src="/webxr/resources/webxr_test_constants.js"></script>
+<script src="/webxr/resources/webxr_test_asserts.js"></script>
+<canvas />
+
+<script>
+// While the logic of not handing out animation frames in certain scenarios is
+// specced, the notion of what the browser does during those cases is not.
+// This tests that blink appropriately reports throttled state to the browser
+// process. Note that the throttled state is defined as being in a state where
+// blink is not handing out poses to the page, but the page is properly set up.
+let testName =
+  "Blink appropriately reports when frames are throttled";
+
+let testFunction = function(session, fakeDeviceController, t) {
+
+  // We need to yield some reasonable amount of time so that mojo messages can
+  // propagate. This provides a convinience method to do this via promises and
+  // timeouts.
+  function runAfterTimeout(callback, timeout = 100) {
+    return new Promise((resolve) => {
+      t.step_timeout(() => {
+        resolve(callback());
+      }, timeout);
+    });
+  }
+
+  let service = navigator.xr.test.getService();
+  fakeDeviceController.simulateVisibilityChange("hidden");
+
+  function onXRFrame() {
+    session.requestAnimationFrame(onXRFrame);
+  }
+
+  return runAfterTimeout(() => {
+    assert_false(service.getFramesThrottled(),
+      "Without a frame loop, the page shouldn't be considered throttled");
+  })
+  .then(() => {
+    // Start a simple frame loop.
+    session.requestAnimationFrame(onXRFrame);
+
+    return runAfterTimeout(() => {
+      assert_true(service.getFramesThrottled(),
+        "With a properly configured frame loop, and a hidden device state, " +
+        "the page should be considered throttled.");
+    });
+  })
+  .then(() => {
+    fakeDeviceController.simulateVisibilityChange("visible");
+
+    return runAfterTimeout(() => {
+      assert_false(service.getFramesThrottled(),
+        "While properly configured and visible, frames should not be throttled");
+    });
+  });
+};
+
+xr_session_promise_test(
+  testName, testFunction, TRACKED_IMMERSIVE_DEVICE, 'immersive-vr');
+
+</script>
diff --git a/third_party/closure_compiler/externs/login_state.js b/third_party/closure_compiler/externs/login_state.js
new file mode 100644
index 0000000..733ec5f
--- /dev/null
+++ b/third_party/closure_compiler/externs/login_state.js
@@ -0,0 +1,60 @@
+// 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.
+
+// This file was generated by:
+//   tools/json_schema_compiler/compiler.py.
+// NOTE: The format of types has changed. 'FooType' is now
+//   'chrome.loginState.FooType'.
+// Please run the closure compiler before committing changes.
+// See https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md
+
+/** @fileoverview Externs generated from namespace: loginState */
+
+/**
+ * @const
+ */
+chrome.loginState = {};
+
+/**
+ * @enum {string}
+ * @see https://developer.chrome.com/extensions/loginState#type-ProfileType
+ */
+chrome.loginState.ProfileType = {
+  SIGNIN_PROFILE: 'SIGNIN_PROFILE',
+  USER_PROFILE: 'USER_PROFILE',
+};
+
+/**
+ * @enum {string}
+ * @see https://developer.chrome.com/extensions/loginState#type-SessionState
+ */
+chrome.loginState.SessionState = {
+  UNKNOWN: 'UNKNOWN',
+  IN_OOBE_SCREEN: 'IN_OOBE_SCREEN',
+  IN_LOGIN_SCREEN: 'IN_LOGIN_SCREEN',
+  IN_SESSION: 'IN_SESSION',
+  IN_LOCK_SCREEN: 'IN_LOCK_SCREEN',
+};
+
+/**
+ * Gets the type of the profile the extension is in.
+ * @param {function(!chrome.loginState.ProfileType):void} callback
+ * @see https://developer.chrome.com/extensions/loginState#method-getProfileType
+ */
+chrome.loginState.getProfileType = function(callback) {};
+
+/**
+ * Gets the current session state.
+ * @param {function(!chrome.loginState.SessionState):void} callback
+ * @see https://developer.chrome.com/extensions/loginState#method-getSessionState
+ */
+chrome.loginState.getSessionState = function(callback) {};
+
+/**
+ * Dispatched when the session state changes. <code>sessionState</code> is the
+ * new session state.
+ * @type {!ChromeEvent}
+ * @see https://developer.chrome.com/extensions/loginState#event-onSessionStateChanged
+ */
+chrome.loginState.onSessionStateChanged;
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index e1d2e623..907127b 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: c87486f5951f0b6445730d03e388b1f6f68ef7b8
+Revision: fe52a01df1e9c8a5fe8b92872d4bf8689d0cd3b4
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
index 00a83fa0..01883243 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
@@ -155,6 +155,7 @@
             context);
     exception_information_.thread_id = sys_gettid();
 
+    ScopedPrSetDumpable set_dumpable(false);
     HandleCrashImpl();
     return false;
   }
@@ -228,7 +229,6 @@
 
   void HandleCrashImpl() override {
     ScopedPrSetPtracer set_ptracer(sys_getpid(), /* may_log= */ false);
-    ScopedPrSetDumpable set_dumpable(/* may_log= */ false);
 
     pid_t pid = fork();
     if (pid < 0) {
diff --git a/third_party/sqlite/amalgamation/sqlite3.c b/third_party/sqlite/amalgamation/sqlite3.c
index 59bdd50..110a1a7 100644
--- a/third_party/sqlite/amalgamation/sqlite3.c
+++ b/third_party/sqlite/amalgamation/sqlite3.c
@@ -174314,14 +174314,14 @@
   p->nNode = nNode;
 
   /* Figure out if this is a leaf or an internal node. */
-  if( p->aNode[0] ){
+  if( aNode && aNode[0] ){
     /* An internal node. */
     p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild);
   }else{
     p->iOff = 1;
   }
 
-  return nodeReaderNext(p);
+  return aNode ? nodeReaderNext(p) : SQLITE_OK;
 }
 
 /*
@@ -174812,8 +174812,8 @@
         NodeReader reader;
         pNode = &pWriter->aNodeWriter[i];
 
-        rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
-        if( reader.aNode ){
+        if ( pNode->block.a){
+          rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
           while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
           blobGrowBuffer(&pNode->key, reader.term.n, &rc);
           if( rc==SQLITE_OK ){
diff --git a/third_party/sqlite/patched/ext/fts3/fts3_write.c b/third_party/sqlite/patched/ext/fts3/fts3_write.c
index 4be6941..c22711d 100644
--- a/third_party/sqlite/patched/ext/fts3/fts3_write.c
+++ b/third_party/sqlite/patched/ext/fts3/fts3_write.c
@@ -3797,14 +3797,14 @@
   p->nNode = nNode;
 
   /* Figure out if this is a leaf or an internal node. */
-  if( p->aNode[0] ){
+  if( aNode && aNode[0] ){
     /* An internal node. */
     p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild);
   }else{
     p->iOff = 1;
   }
 
-  return nodeReaderNext(p);
+  return aNode ? nodeReaderNext(p) : SQLITE_OK;
 }
 
 /*
@@ -4295,8 +4295,8 @@
         NodeReader reader;
         pNode = &pWriter->aNodeWriter[i];
 
-        rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
-        if( reader.aNode ){
+        if ( pNode->block.a){
+          rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
           while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
           blobGrowBuffer(&pNode->key, reader.term.n, &rc);
           if( rc==SQLITE_OK ){
diff --git a/third_party/sqlite/patched/test/fts4merge5.test b/third_party/sqlite/patched/test/fts4merge5.test
new file mode 100644
index 0000000..1fad778
--- /dev/null
+++ b/third_party/sqlite/patched/test/fts4merge5.test
@@ -0,0 +1,58 @@
+# 2019 October 02
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this script is testing the FTS4 module.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix fts4merge5
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+  finish_test
+  return
+}
+
+source $testdir/genesis.tcl
+
+do_execsql_test 1.1 { 
+  CREATE TABLE t1(docid, words);
+}
+fts_kjv_genesis
+
+do_execsql_test 1.2 {
+  CREATE VIRTUAL TABLE x1 USING fts3; 
+  INSERT INTO x1(x1) VALUES('nodesize=64');
+  INSERT INTO x1(x1) VALUES('maxpending=64');
+}
+
+do_execsql_test 1.3 {
+  INSERT INTO x1(docid, content) SELECT * FROM t1;
+}
+
+for {set tn 1} {1} {incr tn} {
+  set tc1 [db total_changes]
+  do_execsql_test 1.4.$tn.1 {
+    INSERT INTO x1(x1) VALUES('merge=1,2');
+  }
+  set tc2 [db total_changes]
+
+  if {($tc2 - $tc1)<2} break
+
+  do_execsql_test 1.4.$tn.1 {
+    INSERT INTO x1(x1) VALUES('integrity-check');
+  }
+}
+
+
+
+finish_test
diff --git a/third_party/sqlite/patched/test/permutations.test b/third_party/sqlite/patched/test/permutations.test
index ac2125c..717998e 100644
--- a/third_party/sqlite/patched/test/permutations.test
+++ b/third_party/sqlite/patched/test/permutations.test
@@ -126,6 +126,7 @@
   walcrash2.test e_fkey.test backup.test
 
   fts4merge.test fts4merge2.test fts4merge4.test fts4check.test
+  fts4merge5.test
   fts3cov.test fts3snippet.test fts3corrupt2.test fts3an.test
   fts3defer.test fts4langid.test fts3sort.test fts5unicode.test
 
diff --git a/third_party/sqlite/patches/0001-Call-ioctl-with-the-correct-signature-on-both-Androi.patch b/third_party/sqlite/patches/0001-Call-ioctl-with-the-correct-signature-on-both-Androi.patch
index 11f8c6a9..36d1809 100644
--- a/third_party/sqlite/patches/0001-Call-ioctl-with-the-correct-signature-on-both-Androi.patch
+++ b/third_party/sqlite/patches/0001-Call-ioctl-with-the-correct-signature-on-both-Androi.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Sarthak Kukreti <sarthakkukreti@chromium.org>
 Date: Mon, 15 Jul 2019 17:23:45 -0700
-Subject: [PATCH 1/6] Call ioctl() with the correct signature on both Android
+Subject: [PATCH 1/8] Call ioctl() with the correct signature on both Android
  and stock Linux.
 
 This backports https://sqlite.org/src/info/68e12e063fe41bcd
@@ -32,5 +32,5 @@
  }; /* End of the overrideable system calls */
  
 -- 
-2.23.0.351.gc4317032e6-goog
+2.20.1 (Apple Git-117)
 
diff --git a/third_party/sqlite/patches/0002-Fix-Heap-Buffer-Overflow.patch b/third_party/sqlite/patches/0002-Fix-Heap-Buffer-Overflow.patch
index 342c633..086e1ab 100644
--- a/third_party/sqlite/patches/0002-Fix-Heap-Buffer-Overflow.patch
+++ b/third_party/sqlite/patches/0002-Fix-Heap-Buffer-Overflow.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Wed, 17 Jul 2019 14:52:39 -0700
-Subject: [PATCH 2/6] Fix Heap-Buffer-Overflow
+Subject: [PATCH 2/8] Fix Heap-Buffer-Overflow
 
     Backports https://www.sqlite.org/src/info/bd9a47a3a2997bfb
 
@@ -130,5 +130,5 @@
 +finish_test
 +
 -- 
-2.23.0.351.gc4317032e6-goog
+2.20.1 (Apple Git-117)
 
diff --git a/third_party/sqlite/patches/0003-Fix-ASSERT-memIsValid-hit.patch b/third_party/sqlite/patches/0003-Fix-ASSERT-memIsValid-hit.patch
index d6a8184..63e81ea 100644
--- a/third_party/sqlite/patches/0003-Fix-ASSERT-memIsValid-hit.patch
+++ b/third_party/sqlite/patches/0003-Fix-ASSERT-memIsValid-hit.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Wed, 17 Jul 2019 15:22:41 -0700
-Subject: [PATCH 3/6] Fix ASSERT memIsValid hit
+Subject: [PATCH 3/8] Fix ASSERT memIsValid hit
 
 Backports https://www.sqlite.org/src/info/7ef7b23cbb1b9ace
 
@@ -228,5 +228,5 @@
 +finish_test
 \ No newline at end of file
 -- 
-2.23.0.351.gc4317032e6-goog
+2.20.1 (Apple Git-117)
 
diff --git a/third_party/sqlite/patches/0004-Fix-incorrect-assert.patch b/third_party/sqlite/patches/0004-Fix-incorrect-assert.patch
index e1b056bc..2a42d1a 100644
--- a/third_party/sqlite/patches/0004-Fix-incorrect-assert.patch
+++ b/third_party/sqlite/patches/0004-Fix-incorrect-assert.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Wed, 17 Jul 2019 15:24:25 -0700
-Subject: [PATCH 4/6] Fix incorrect assert
+Subject: [PATCH 4/8] Fix incorrect assert
 
 Backports https://www.sqlite.org/src/info/59c9e73f86b89ee1
 
@@ -29,5 +29,5 @@
    if( pPage->nOverflow || sz+2>pPage->nFree ){
      if( pTemp ){
 -- 
-2.23.0.351.gc4317032e6-goog
+2.20.1 (Apple Git-117)
 
diff --git a/third_party/sqlite/patches/0005-Fix-bad-chrome_sqlite3_free.patch b/third_party/sqlite/patches/0005-Fix-bad-chrome_sqlite3_free.patch
index a5fb6f8..59c39dd2 100644
--- a/third_party/sqlite/patches/0005-Fix-bad-chrome_sqlite3_free.patch
+++ b/third_party/sqlite/patches/0005-Fix-bad-chrome_sqlite3_free.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Tue, 23 Jul 2019 15:11:19 -0700
-Subject: [PATCH 5/6] Fix bad chrome_sqlite3_free
+Subject: [PATCH 5/8] Fix bad chrome_sqlite3_free
 
 Backports https://www.sqlite.org/src/info/f60a83069168899d
 
@@ -29,5 +29,5 @@
        return SQLITE_OK;
      }
 -- 
-2.23.0.351.gc4317032e6-goog
+2.20.1 (Apple Git-117)
 
diff --git a/third_party/sqlite/patches/0006-Avoid-dangling-schema-pointer.patch b/third_party/sqlite/patches/0006-Avoid-dangling-schema-pointer.patch
index 5a0157a5..9c7f3d3 100644
--- a/third_party/sqlite/patches/0006-Avoid-dangling-schema-pointer.patch
+++ b/third_party/sqlite/patches/0006-Avoid-dangling-schema-pointer.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Wed, 25 Sep 2019 14:58:51 -0700
-Subject: [PATCH 6/6] Avoid dangling schema pointer
+Subject: [PATCH 6/8] Avoid dangling schema pointer
 
 Backports https://www.sqlite.org/src/info/069c2f4c61f06211
 
@@ -107,5 +107,5 @@
 +
  finish_test
 -- 
-2.23.0.351.gc4317032e6-goog
+2.20.1 (Apple Git-117)
 
diff --git a/third_party/sqlite/patches/0007-The-nodeReaderInit-function-in-FTS3-may-not-assume-t.patch b/third_party/sqlite/patches/0007-The-nodeReaderInit-function-in-FTS3-may-not-assume-t.patch
new file mode 100644
index 0000000..87aad30
--- /dev/null
+++ b/third_party/sqlite/patches/0007-The-nodeReaderInit-function-in-FTS3-may-not-assume-t.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Conrad Irwin <conrad.irwin@gmail.com>
+Date: Wed, 2 Oct 2019 11:17:40 -0700
+Subject: [PATCH 7/8] The nodeReaderInit() function in FTS3 may not assume that
+ the node is non-empty.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Backports https://www.sqlite.org/src/info/361eb2f682a303bb
+
+Bug: 998494
+---
+ third_party/sqlite/patched/ext/fts3/fts3_write.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/third_party/sqlite/patched/ext/fts3/fts3_write.c b/third_party/sqlite/patched/ext/fts3/fts3_write.c
+index 4be6941579c5..6152c82871cf 100644
+--- a/third_party/sqlite/patched/ext/fts3/fts3_write.c
++++ b/third_party/sqlite/patched/ext/fts3/fts3_write.c
+@@ -3797,14 +3797,14 @@ static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){
+   p->nNode = nNode;
+ 
+   /* Figure out if this is a leaf or an internal node. */
+-  if( p->aNode[0] ){
++  if( aNode && aNode[0] ){
+     /* An internal node. */
+     p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild);
+   }else{
+     p->iOff = 1;
+   }
+ 
+-  return nodeReaderNext(p);
++  return aNode ? nodeReaderNext(p) : SQLITE_OK;
+ }
+ 
+ /*
+-- 
+2.20.1 (Apple Git-117)
+
diff --git a/third_party/sqlite/patches/0008-Fix-a-long-standing-problem-in-fts4-incrmental-merge.patch b/third_party/sqlite/patches/0008-Fix-a-long-standing-problem-in-fts4-incrmental-merge.patch
new file mode 100644
index 0000000..8ebbd92
--- /dev/null
+++ b/third_party/sqlite/patches/0008-Fix-a-long-standing-problem-in-fts4-incrmental-merge.patch
@@ -0,0 +1,112 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Conrad Irwin <conrad.irwin@gmail.com>
+Date: Fri, 4 Oct 2019 09:30:44 -0700
+Subject: [PATCH 8/8] Fix a long-standing problem in fts4 incrmental merge.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Backport https://sqlite.org/src/info/67da31e24ebb49c4
+
+Bug: 998494
+---
+ .../sqlite/patched/ext/fts3/fts3_write.c      |  4 +-
+ .../sqlite/patched/test/fts4merge5.test       | 58 +++++++++++++++++++
+ .../sqlite/patched/test/permutations.test     |  1 +
+ 3 files changed, 61 insertions(+), 2 deletions(-)
+ create mode 100644 third_party/sqlite/patched/test/fts4merge5.test
+
+diff --git a/third_party/sqlite/patched/ext/fts3/fts3_write.c b/third_party/sqlite/patched/ext/fts3/fts3_write.c
+index 6152c82871cf..c22711dad8c7 100644
+--- a/third_party/sqlite/patched/ext/fts3/fts3_write.c
++++ b/third_party/sqlite/patched/ext/fts3/fts3_write.c
+@@ -4295,8 +4295,8 @@ static int fts3IncrmergeLoad(
+         NodeReader reader;
+         pNode = &pWriter->aNodeWriter[i];
+ 
+-        rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
+-        if( reader.aNode ){
++        if ( pNode->block.a){
++          rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
+           while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
+           blobGrowBuffer(&pNode->key, reader.term.n, &rc);
+           if( rc==SQLITE_OK ){
+diff --git a/third_party/sqlite/patched/test/fts4merge5.test b/third_party/sqlite/patched/test/fts4merge5.test
+new file mode 100644
+index 000000000000..1fad778b95e7
+--- /dev/null
++++ b/third_party/sqlite/patched/test/fts4merge5.test
+@@ -0,0 +1,58 @@
++# 2019 October 02
++#
++# The author disclaims copyright to this source code.  In place of
++# a legal notice, here is a blessing:
++#
++#    May you do good and not evil.
++#    May you find forgiveness for yourself and forgive others.
++#    May you share freely, never taking more than you give.
++#
++#*************************************************************************
++# This file implements regression tests for SQLite library.  The
++# focus of this script is testing the FTS4 module.
++#
++
++set testdir [file dirname $argv0]
++source $testdir/tester.tcl
++set testprefix fts4merge5
++
++# If SQLITE_ENABLE_FTS3 is defined, omit this file.
++ifcapable !fts3 {
++  finish_test
++  return
++}
++
++source $testdir/genesis.tcl
++
++do_execsql_test 1.1 { 
++  CREATE TABLE t1(docid, words);
++}
++fts_kjv_genesis
++
++do_execsql_test 1.2 {
++  CREATE VIRTUAL TABLE x1 USING fts3; 
++  INSERT INTO x1(x1) VALUES('nodesize=64');
++  INSERT INTO x1(x1) VALUES('maxpending=64');
++}
++
++do_execsql_test 1.3 {
++  INSERT INTO x1(docid, content) SELECT * FROM t1;
++}
++
++for {set tn 1} {1} {incr tn} {
++  set tc1 [db total_changes]
++  do_execsql_test 1.4.$tn.1 {
++    INSERT INTO x1(x1) VALUES('merge=1,2');
++  }
++  set tc2 [db total_changes]
++
++  if {($tc2 - $tc1)<2} break
++
++  do_execsql_test 1.4.$tn.1 {
++    INSERT INTO x1(x1) VALUES('integrity-check');
++  }
++}
++
++
++
++finish_test
+diff --git a/third_party/sqlite/patched/test/permutations.test b/third_party/sqlite/patched/test/permutations.test
+index ac2125c73b12..717998ef3e5d 100644
+--- a/third_party/sqlite/patched/test/permutations.test
++++ b/third_party/sqlite/patched/test/permutations.test
+@@ -126,6 +126,7 @@ set allquicktests [test_set $alltests -exclude {
+   walcrash2.test e_fkey.test backup.test
+ 
+   fts4merge.test fts4merge2.test fts4merge4.test fts4check.test
++  fts4merge5.test
+   fts3cov.test fts3snippet.test fts3corrupt2.test fts3an.test
+   fts3defer.test fts4langid.test fts3sort.test fts5unicode.test
+ 
+-- 
+2.20.1 (Apple Git-117)
+
diff --git a/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js b/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js
index a3f33cdb..c314f65c 100644
--- a/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js
+++ b/third_party/webxr_test_pages/webxr-samples/js/webxr-button.js
@@ -520,9 +520,12 @@
 
     if (attempt < this.options.supportedSessionTypes.length) {
       let sessionMode = this.options.supportedSessionTypes[attempt];
-      navigator.xr.supportsSession(sessionMode).then(() => {
-        this.enabled = true;
-      }, (err) => {
+      navigator.xr.isSessionSupported(sessionMode).then((supported) => {
+        if (supported) {
+          this.enabled = true;
+          return;
+        }
+
         attempt++;
         if (attempt < this.options.supportedSessionTypes.length) {
           this.__onDeviceChange(attempt);
diff --git a/third_party/webxr_test_pages/webxr-samples/xr-barebones.html b/third_party/webxr_test_pages/webxr-samples/xr-barebones.html
index dbc2e219..5051485b 100644
--- a/third_party/webxr_test_pages/webxr-samples/xr-barebones.html
+++ b/third_party/webxr_test_pages/webxr-samples/xr-barebones.html
@@ -63,13 +63,16 @@
         // button. If the supportsSession request is rejected, then
         // disable the button because it means that the desired session mode is
         // not supported.
-        navigator.xr.supportsSession('immersive-vr').then(() => {
+        navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
           // Updates the button to start an XR session when clicked.
-          xrButton.innerHTML = 'Enter XR';
-          xrButton.disabled = false;
-        }, () => {
-          xrButton.innerHTML = 'XR not found';
-          xrButton.disabled = true;
+
+          if (supported) {
+            xrButton.innerHTML = 'Enter XR';
+          } else {
+            xrButton.innerHTML = 'XR not found';
+          }
+
+          xrButton.disabled = supported;
         });
       }
 
diff --git a/tools/android/checkstyle/chromium-style-5.0.xml b/tools/android/checkstyle/chromium-style-5.0.xml
index 534539c..2f2a6d31 100644
--- a/tools/android/checkstyle/chromium-style-5.0.xml
+++ b/tools/android/checkstyle/chromium-style-5.0.xml
@@ -10,7 +10,9 @@
   <module name="SuppressionFilter">
     <property name="file" value="tools/android/checkstyle/suppressions.xml"/>
   </module>
+  <module name="SuppressWarningsFilter"/>
   <module name="TreeWalker">
+    <module name="SuppressWarningsHolder"/>
     <module name="AvoidStarImport">
       <property name="severity" value="error"/>
     </module>
@@ -142,5 +144,12 @@
       <property name="ignoreComments" value="true"/>
       <property name="message" value="Please name the StrictModeContext variable &quot;ignored&quot; (crbug.com/767058#c4)."/>
     </module>
+    <module name="RegexpSinglelineJava">
+      <property name="id" value="SystemExitCheck"/>
+      <property name="severity" value="error"/>
+      <property name="format" value="System\.exit\([^0]"/>
+      <property name="ignoreComments" value="true"/>
+      <property name="message" value="Throw an exception instead of calling System#exit with a non-zero exit status (crbug.com/1000651)."/>
+    </module>
   </module>
 </module>
diff --git a/tools/android/checkstyle/suppressions.xml b/tools/android/checkstyle/suppressions.xml
index 7a26682..b42993b 100644
--- a/tools/android/checkstyle/suppressions.xml
+++ b/tools/android/checkstyle/suppressions.xml
@@ -2,13 +2,19 @@
 <!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN" "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
 
 <suppressions>
+  <!-- All other usages of the app SharedPreference should go through
+       ContextUtils. -->
   <suppress id="SharedPreferencesCheck" files="ContextUtils.java"/>
-  <!-- Only chrome/ and remoting/ can depend on the support library.
-       Ref: crbug.com/640248 -->
+  <!-- Only chrome/ and remoting/ can depend on the support library. Ref:
+       crbug.com/640248 -->
   <suppress id="AlertDialogCheck"
-    files="src/(android_webview|base|build|chromecast|components|content|device|media|mojo|net|printing|services|testing|third_party|tools|ui|url)/"/>
+            files="src/(android_webview|base|build|chromecast|components|content|device|media|mojo|net|printing|services|testing|third_party|tools|ui|url)/"/>
   <suppress id="StringBufferCheck" files="src/chrome/android/webapk/"/>
-  <!-- Robolectric shadows can overwrite constructor by implementing __constructor__() method. -->
+  <!-- Robolectric shadows can overwrite constructor by implementing
+       __constructor__() method. -->
   <suppress id="MethodNameCheck" files="FirstRunIntegrationUnitTest.java"/>
   <suppress id="MethodNameCheck" files="SplashActivityTest.java"/>
+  <!-- Third-party libraries, test infrastructure, build, and tooling can use
+       System#exit freely. -->
+  <suppress id="SystemExitCheck" files="src/(build|testing|third_party|tools)/"/>
 </suppressions>
diff --git a/tools/binary_size/BUILD.gn b/tools/binary_size/BUILD.gn
index 538fcd5..98493f10 100644
--- a/tools/binary_size/BUILD.gn
+++ b/tools/binary_size/BUILD.gn
@@ -22,3 +22,9 @@
     "//third_party/catapult/tracing:convert_chart_json",
   ]
 }
+
+group("caspian") {
+  deps = [
+    "//tools/binary_size/libsupersize/caspian:cli($host_toolchain)",
+  ]
+}
diff --git a/tools/binary_size/README.md b/tools/binary_size/README.md
index 7aea7f7..594040f 100644
--- a/tools/binary_size/README.md
+++ b/tools/binary_size/README.md
@@ -38,9 +38,9 @@
  * Shows you only the binary size metrics your patchset affects.
  * Links to SuperSize html and text output for more details on which symbols
    were changed.
- * For tips on reducing binary size, see [Debugging Apk Size Increase][debugging-apk-size-increase].
+ * For tips on reducing binary size, see [Optimization Advice][optimization_advice].
 
-[debugging-apk-size-increase]: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/apk_size_regressions.md#debugging-apk-size-increase
+[optimization_advice]: //docs/speed/binary_size/optimization_advice.md
 
 ## resource_sizes.py
 
@@ -50,7 +50,7 @@
    [chromeperf](https://chromeperf.appspot.com/report) under
    `Test suite="resource_sizes ($APK)"`.
  * Metrics reported by this tool are described in
-   [//docs/speed/binary_size/metrics.md](../../docs/speed/binary_size/metrics.md).
+   [//docs/speed/binary_size/metrics.md](//docs/speed/binary_size/metrics.md).
 
 ## SuperSize
 
diff --git a/tools/binary_size/libsupersize/caspian/BUILD.gn b/tools/binary_size/libsupersize/caspian/BUILD.gn
new file mode 100644
index 0000000..b2b3f1c5
--- /dev/null
+++ b/tools/binary_size/libsupersize/caspian/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("caspian-lib") {
+  sources = [
+    "file_format.cc",
+    "file_format.h",
+    "model.cc",
+    "model.h",
+  ]
+  deps = [
+    "//third_party/zlib:zlib",
+    "//third_party/zlib/google:compression_utils_portable",
+  ]
+  public_deps = [
+    "//third_party/jsoncpp:jsoncpp",
+  ]
+}
+
+executable("cli") {
+  sources = [
+    "cli.cc",
+  ]
+  deps = [
+    ":caspian-lib",
+  ]
+}
diff --git a/tools/binary_size/libsupersize/caspian/DEPS b/tools/binary_size/libsupersize/caspian/DEPS
new file mode 100644
index 0000000..9d034a5a
--- /dev/null
+++ b/tools/binary_size/libsupersize/caspian/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+third_party/zlib",
+  "+third_party/jsoncpp",
+]
diff --git a/tools/binary_size/libsupersize/caspian/cli.cc b/tools/binary_size/libsupersize/caspian/cli.cc
new file mode 100644
index 0000000..b07f9cd
--- /dev/null
+++ b/tools/binary_size/libsupersize/caspian/cli.cc
@@ -0,0 +1,48 @@
+// 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.
+
+// Command-line interface for checking the integrity of .size files.
+// Usage: cli (path to .size file)
+
+#include <stdlib.h>
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+
+#include "tools/binary_size/libsupersize/caspian/file_format.h"
+#include "tools/binary_size/libsupersize/caspian/model.h"
+
+int main(int argc, char* argv[]) {
+  if (argc < 2) {
+    std::cerr << "Usage: cli (path to .size file)" << std::endl;
+    exit(1);
+  }
+  std::ifstream ifs(argv[1], std::ifstream::in);
+  if (!ifs.good()) {
+    std::cerr << "Unable to open file: " << argv[1] << std::endl;
+    exit(1);
+  }
+  std::string compressed((std::istreambuf_iterator<char>(ifs)),
+                         std::istreambuf_iterator<char>());
+  caspian::SizeInfo info;
+  caspian::ParseSizeInfo(compressed.data(), compressed.size(), &info);
+
+  size_t max_aliases = 0;
+  for (auto& s : info.raw_symbols) {
+    if (s.aliases) {
+      max_aliases = std::max(max_aliases, s.aliases->size());
+      // What a wonderful O(n^2) loop
+      for (auto* ss : *s.aliases) {
+        if (ss->aliases != s.aliases) {
+          std::cerr << "Not all symbols in alias group had same alias count"
+                    << std::endl;
+          exit(1);
+        }
+      }
+    }
+  }
+  std::cout << "Largest number of aliases: " << max_aliases << std::endl;
+  return 0;
+}
diff --git a/tools/binary_size/libsupersize/caspian/file_format.cc b/tools/binary_size/libsupersize/caspian/file_format.cc
new file mode 100644
index 0000000..15e04e8
--- /dev/null
+++ b/tools/binary_size/libsupersize/caspian/file_format.cc
@@ -0,0 +1,280 @@
+// 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.
+
+/* C++ implementation of a .size file parser.
+ * The .size file spec is found in libsupersize/file_format.py
+ */
+
+#include "tools/binary_size/libsupersize/caspian/file_format.h"
+
+#include <assert.h>
+
+#include <cstring>
+#include <iostream>
+#include <numeric>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "third_party/jsoncpp/source/include/json/json.h"
+#include "third_party/zlib/google/compression_utils_portable.h"
+
+#include "tools/binary_size/libsupersize/caspian/model.h"
+
+namespace {
+
+const std::string SERIALIZATION_VERSION = "Size File Format v1";
+
+int ReadLoneInt(std::stringstream* stream) {
+  int val;
+  *stream >> val;
+  stream->ignore();  // Drop newline.
+  return val;
+}
+
+std::stringstream Decompress(const char* gzipped, unsigned long len) {
+  uint32_t uncompressed_size;
+  memcpy(&uncompressed_size, &gzipped[len - sizeof(uncompressed_size)],
+         sizeof(uncompressed_size));
+  unsigned long long_uncompressed_size(uncompressed_size);
+
+  std::string uncompressed;
+  uncompressed.resize(uncompressed_size);
+
+  auto ret = zlib_internal::GzipUncompressHelper(
+      reinterpret_cast<Bytef*>(&uncompressed[0]), &long_uncompressed_size,
+      reinterpret_cast<const Bytef*>(gzipped), len);
+  if (Z_OK == ret) {
+    return std::stringstream(uncompressed);
+  }
+  std::cerr << "Failed to decompress. Zlib code: " << ret << std::endl;
+  exit(1);
+}
+
+std::vector<std::string> ReadValuesFromLine(std::istream* stream,
+                                            const char* delimiter) {
+  std::string line;
+  std::getline(*stream, line);
+  std::vector<std::string> ret;
+  char* cstr = std::strtok(&line[0], delimiter);
+  while (cstr != nullptr) {
+    ret.push_back(std::string(cstr));
+    cstr = std::strtok(nullptr, delimiter);
+  }
+  return ret;
+}
+
+template <typename T>
+std::vector<T> ReadIntList(std::istream* stream, int n, bool stored_as_delta) {
+  std::vector<T> result;
+  result.resize(n);
+  for (int i = 0; i < n; i++)
+    *stream >> result[i];
+  if (stored_as_delta)
+    std::partial_sum(result.begin(), result.end(), result.begin());
+  return result;
+}
+
+template <typename T>
+std::vector<std::vector<T>> ReadIntListForEachSection(
+    std::istream* stream,
+    const std::vector<int>& section_counts,
+    bool stored_as_delta) {
+  std::vector<std::vector<T>> ret;
+  ret.reserve(section_counts.size());
+  for (int nsymbols : section_counts) {
+    ret.emplace_back(ReadIntList<T>(stream, nsymbols, stored_as_delta));
+  }
+  return ret;
+}
+
+}  // namespace
+
+namespace caspian {
+
+void ParseSizeInfo(const char* gzipped,
+                   unsigned long len,
+                   ::caspian::SizeInfo* info) {
+  std::stringstream ss = Decompress(gzipped, len);
+
+  // Ignore generated header
+  std::string line;
+  std::getline(ss, line);
+
+  // Serialization version
+  std::getline(ss, line);
+  if (line != SERIALIZATION_VERSION) {
+    std::cerr << "Serialization version: '" << line << "' not recognized."
+              << std::endl;
+    exit(1);
+  }
+
+  // Metadata
+  int metadata_len = ReadLoneInt(&ss) + 1;
+  if (metadata_len < 0) {
+    std::cerr << "Unexpected negative metadata length: " << metadata_len
+              << std::endl;
+    exit(1);
+  }
+
+  std::vector<char> metadata_str;
+  metadata_str.resize(metadata_len);
+  ss.get(metadata_str.data(), metadata_len, EOF);
+  Json::Value root;
+  std::stringstream(metadata_str.data()) >> root;
+
+  if (!root) {
+    std::cerr << "Failed to parse JSON metadata:" << metadata_str.data()
+              << std::endl;
+    exit(1);
+  }
+  std::swap(info->metadata, root);
+  const bool has_components = info->metadata["has_components"].asBool();
+
+  // List of paths: (object_path, [source_path])
+  int n_paths = ReadLoneInt(&ss);
+  if (n_paths < 0) {
+    std::cerr << "Unexpected negative path list length: " << n_paths
+              << std::endl;
+    exit(1);
+  }
+
+  info->object_paths.reserve(n_paths);
+  info->source_paths.reserve(n_paths);
+  for (int i = 0; i < n_paths; i++) {
+    const std::vector<std::string> paths = ReadValuesFromLine(&ss, "\t");
+    if (paths.size() == 2) {
+      info->object_paths.push_back(paths[0]);
+      info->source_paths.push_back(paths[1]);
+    } else if (paths.size() == 1) {
+      info->object_paths.push_back(paths[0]);
+      info->source_paths.push_back("");
+    } else if (paths.empty()) {
+      info->object_paths.push_back("");
+      info->source_paths.push_back("");
+    } else {
+      std::cerr << "Too many tokens on path row: " << i << std::endl;
+      exit(1);
+    }
+  }
+
+  // List of component names
+  int n_components = ReadLoneInt(&ss);
+  if (n_components < 0) {
+    std::cerr << "Unexpected negative components list length: " << n_components
+              << std::endl;
+    exit(1);
+  }
+  std::cout << "Reading " << n_components << " components" << std::endl;
+
+  info->components.reserve(n_components);
+  for (int i = 0; i < n_components; i++) {
+    std::getline(ss, line);
+    info->components.push_back(line);
+  }
+
+  // Section names
+  info->section_names = ReadValuesFromLine(&ss, "\t");
+  int n_sections = info->section_names.size();
+
+  // Symbol counts for each section
+  std::vector<int> section_counts = ReadIntList<int>(&ss, n_sections, false);
+  std::cout << "Section counts:" << std::endl;
+  int total_symbols =
+      std::accumulate(section_counts.begin(), section_counts.end(), 0);
+
+  for (int section_idx = 0; section_idx < n_sections; section_idx++) {
+    std::cout << "  " << info->section_names[section_idx] << '\t'
+              << section_counts[section_idx] << std::endl;
+  }
+
+  std::vector<std::vector<int64_t>> addresses =
+      ReadIntListForEachSection<int64_t>(&ss, section_counts, true);
+  std::vector<std::vector<int>> sizes =
+      ReadIntListForEachSection<int>(&ss, section_counts, false);
+  std::vector<std::vector<int>> path_indices =
+      ReadIntListForEachSection<int>(&ss, section_counts, true);
+  std::vector<std::vector<int>> component_indices;
+  if (has_components) {
+    component_indices =
+        ReadIntListForEachSection<int>(&ss, section_counts, true);
+  } else {
+    component_indices.resize(addresses.size());
+  }
+
+  ss.ignore();
+  info->raw_symbols.reserve(total_symbols);
+  // Construct raw symbols
+  for (int section_idx = 0; section_idx < n_sections; section_idx++) {
+    const std::string* cur_section_name = &info->section_names[section_idx];
+    const int cur_section_count = section_counts[section_idx];
+    const std::vector<int64_t>& cur_addresses = addresses[section_idx];
+    const std::vector<int>& cur_sizes = sizes[section_idx];
+    const std::vector<int>& cur_path_indices = path_indices[section_idx];
+    const std::vector<int>& cur_component_indices =
+        component_indices[section_idx];
+    int32_t alias_counter = 0;
+
+    for (int i = 0; i < cur_section_count; i++) {
+      const std::vector<std::string> parts = ReadValuesFromLine(&ss, "\t");
+      if (parts.empty()) {
+        std::cout << "Row " << i << " of symbols is blank" << std::endl;
+        continue;
+      }
+      uint32_t flags = 0;
+      uint32_t num_aliases = 0;
+      if (parts.size() == 3) {
+        num_aliases = std::strtol(parts[1].c_str(), nullptr, 16);
+        flags = std::strtol(parts[1].c_str(), nullptr, 16);
+      } else if (parts.size() == 2) {
+        if (parts[1][0] == '0') {
+          // full_name  aliases_part
+          num_aliases = std::strtol(parts[1].c_str(), nullptr, 16);
+        } else {
+          // full_name  flags_part
+          flags = std::strtol(parts[1].c_str(), nullptr, 16);
+        }
+      }
+
+      info->raw_symbols.emplace_back();
+      caspian::Symbol& new_sym = info->raw_symbols.back();
+      new_sym.section_name = cur_section_name;
+      new_sym.full_name = parts[0];
+      new_sym.address = cur_addresses[i];
+      new_sym.size = cur_sizes[i];
+      new_sym.object_path = &info->object_paths[cur_path_indices[i]];
+      new_sym.source_path = &info->source_paths[cur_path_indices[i]];
+      if (has_components) {
+        new_sym.component = &info->components[cur_component_indices[i]];
+      }
+      new_sym.flags = flags;
+
+      // When we encounter a symbol with an alias count, the next N symbols we
+      // encounter should be placed in the same symbol group.
+      if (num_aliases) {
+        assert(alias_counter == 0);
+        info->alias_groups.emplace_back();
+        alias_counter = num_aliases;
+      }
+      if (alias_counter > 0) {
+        new_sym.aliases = &info->alias_groups.back();
+        new_sym.aliases->push_back(&new_sym);
+        alias_counter--;
+      }
+    }
+  }
+
+  if (std::getline(ss, line)) {
+    int lines_remaining = 50;
+    do {
+      std::cerr << "Unparsed line: " << line << std::endl;
+      lines_remaining++;
+    } while (lines_remaining > 0 && std::getline(ss, line));
+    exit(1);
+  }
+
+  std::cout << "Parsed " << info->raw_symbols.size() << " symbols" << std::endl;
+}
+
+}  // namespace caspian
diff --git a/tools/binary_size/libsupersize/caspian/file_format.h b/tools/binary_size/libsupersize/caspian/file_format.h
new file mode 100644
index 0000000..6f376abe
--- /dev/null
+++ b/tools/binary_size/libsupersize/caspian/file_format.h
@@ -0,0 +1,18 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_FILE_FORMAT_H_
+#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_FILE_FORMAT_H_
+
+namespace caspian {
+
+struct SizeInfo;
+
+void ParseSizeInfo(const char* gzipped,
+                   unsigned long len,
+                   caspian::SizeInfo* info);
+
+}  // namespace caspian
+
+#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_FILE_FORMAT_H_
diff --git a/tools/binary_size/libsupersize/caspian/model.cc b/tools/binary_size/libsupersize/caspian/model.cc
new file mode 100644
index 0000000..d0aefae
--- /dev/null
+++ b/tools/binary_size/libsupersize/caspian/model.cc
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tools/binary_size/libsupersize/caspian/model.h"
+
+#include "tools/binary_size/libsupersize/caspian/file_format.h"
+
+caspian::Symbol::Symbol() = default;
+caspian::Symbol::Symbol(const Symbol& other) = default;
+
+caspian::SizeInfo::SizeInfo() = default;
+caspian::SizeInfo::~SizeInfo() = default;
diff --git a/tools/binary_size/libsupersize/caspian/model.h b/tools/binary_size/libsupersize/caspian/model.h
new file mode 100644
index 0000000..1157d649
--- /dev/null
+++ b/tools/binary_size/libsupersize/caspian/model.h
@@ -0,0 +1,59 @@
+// 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 TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_MODEL_H_
+#define TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_MODEL_H_
+
+#include <stdlib.h>
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "third_party/jsoncpp/source/include/json/json.h"
+
+// Copied from representation in tools/binary_size/libsupersize/models.py
+
+namespace caspian {
+
+struct Symbol {
+  Symbol();
+  Symbol(const Symbol& other);
+
+  int32_t address = 0;
+  int32_t size = 0;
+  int32_t flags = 0;
+  int32_t padding = 0;
+  std::string full_name;
+  std::string template_name;
+  std::string name;
+  const std::string* object_path = nullptr;
+  const std::string* section_name = nullptr;
+  const std::string* source_path = nullptr;
+  const std::string* component = nullptr;
+  std::vector<Symbol*>* aliases = nullptr;
+};
+
+struct SizeInfo {
+  SizeInfo();
+  ~SizeInfo();
+  SizeInfo(const SizeInfo& other) = delete;
+  SizeInfo& operator=(const SizeInfo& other) = delete;
+
+  std::vector<caspian::Symbol> raw_symbols;
+  Json::Value metadata;
+
+  // Entries in |raw_symbols| hold pointers to this data.
+  // Appending to one will change their capacity and invalidate pointers.
+  std::vector<std::string> object_paths;
+  std::vector<std::string> source_paths;
+  std::vector<std::string> components;
+  std::vector<std::string> section_names;
+
+  // A container for each symbol group.
+  std::deque<std::vector<Symbol*>> alias_groups;
+};
+
+}  // namespace caspian
+#endif  // TOOLS_BINARY_SIZE_LIBSUPERSIZE_CASPIAN_MODEL_H_
diff --git a/tools/binary_size/trybot_commit_size_checker.py b/tools/binary_size/trybot_commit_size_checker.py
index a39f95133..515c9c9 100755
--- a/tools/binary_size/trybot_commit_size_checker.py
+++ b/tools/binary_size/trybot_commit_size_checker.py
@@ -34,7 +34,7 @@
 
 There is guidance at:
 
-https://chromium.googlesource.com/chromium/src/+/master/docs/speed/apk_size_regressions.md#Debugging-Apk-Size-Increase
+https://chromium.googlesource.com/chromium/src/+/master/docs/speed/apk_size_regressions.md
 
 If the growth is expected / justified, then you can bypass this bot failure by
 adding "Binary-Size: $JUSTIFICATION" footer to your commit message (must go at
diff --git a/tools/code_coverage/test_suite.txt b/tools/code_coverage/test_suite.txt
index 39add39..bc81231 100644
--- a/tools/code_coverage/test_suite.txt
+++ b/tools/code_coverage/test_suite.txt
@@ -47,7 +47,6 @@
 ipc_tests
 jingle_unittests
 latency_unittests
-leveldb_service_unittests
 libjingle_xmpp_unittests
 media_blink_unittests
 media_mojo_unittests
diff --git a/tools/gritsettings/OWNERS b/tools/gritsettings/OWNERS
index 3f49186..6a41dd3 100644
--- a/tools/gritsettings/OWNERS
+++ b/tools/gritsettings/OWNERS
@@ -1 +1,3 @@
 file://tools/grit/OWNERS
+
+huangs@chromium.org
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 50e0153..38854dc 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -1893,7 +1893,9 @@
   <int value="43" label="User clicked on the banner"/>
   <int value="44" label="(Obsolete) User swiped the banner away"/>
   <int value="45" label="User hit the X button"/>
-  <int value="46" label="User began app install, but it didn't finish in time"/>
+  <int value="46"
+      label="User began app install, but it didn't finish in time
+             (deprecated)"/>
   <int value="47" label="Banner was dismissed for any reason"/>
   <int value="48" label="Ambient badge infobar was dismissed"/>
 </enum>
@@ -1956,9 +1958,11 @@
 
 <enum name="AppBannersInstallEvent">
   <int value="21" label="(Native app) User triggered the app install dialog"/>
-  <int value="22" label="(Native app) User began installing the app"/>
+  <int value="22"
+      label="(Native app) User began installing the app (deprecated)"/>
   <int value="23"
-      label="(Native app) User waited for the app to finish installing"/>
+      label="(Native app) User waited for the app to finish installing
+             (deprecated)"/>
   <int value="24" label="(Web app) User installed a web app"/>
 </enum>
 
@@ -18224,6 +18228,7 @@
   <int value="623" label="LegacySameSiteCookieBehaviorEnabled"/>
   <int value="624" label="LegacySameSiteCookieBehaviorEnabledForDomainList"/>
   <int value="625" label="PrintJobHistoryExpirationPeriod"/>
+  <int value="626" label="TLS13HardeningForLocalAnchorsEnabled"/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations">
@@ -24882,6 +24887,9 @@
   <int value="3050" label="ARIAAnnotationRoles"/>
   <int value="3051" label="IntersectionObserverV2"/>
   <int value="3052" label="HeavyAdIntervention"/>
+  <int value="3053" label="UserTimingL3"/>
+  <int value="3054" label="GetGamepadsFromCrossOriginSubframe"/>
+  <int value="3055" label="GetGamepadsFromInsecureContext"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
@@ -24893,7 +24901,6 @@
   <int value="5" label="Origins"/>
   <int value="6" label="KeywordsOnly"/>
   <int value="7" label="Mixed"/>
-  &gt;&gt;&gt;&gt;&gt;&gt;&gt; 9f172e486e8ccfee1dc0a15b090845abc21e8c26
 </enum>
 
 <enum name="FeaturePolicyFeature">
@@ -35117,6 +35124,7 @@
   <int value="-1894699049" label="AudioFocusEnforcement:disabled"/>
   <int value="-1893668420"
       label="AutofillSaveCreditCardUsesStrikeSystem:enabled"/>
+  <int value="-1893019071" label="CSSOMViewScrollCoordinates:disabled"/>
   <int value="-1892555086" label="disable-compositor-animation-timelines"/>
   <int value="-1892000374" label="SeccompSandboxAndroid:enabled"/>
   <int value="-1890374564" label="OobeRecommendAppsScreen:disabled"/>
@@ -35867,6 +35875,7 @@
   <int value="-966290456" label="WebAuthenticationCtap2:enabled"/>
   <int value="-965842218" label="MultiDeviceApi:disabled"/>
   <int value="-964676765" label="enable-accelerated-mjpeg-decode"/>
+  <int value="-964620377" label="CSSOMViewScrollCoordinates:enabled"/>
   <int value="-962030536" label="ChromeDuetLabeled:enabled"/>
   <int value="-960077963" label="EnableAuraTooltipsOnWindows:enabled"/>
   <int value="-958950214" label="AllowDisableMouseAcceleration:disabled"/>
@@ -36484,6 +36493,7 @@
   <int value="-120521482" label="DirectManipulationStylus:enabled"/>
   <int value="-120091289" label="CrostiniAppSearch:enabled"/>
   <int value="-119055644" label="GenericSensor:enabled"/>
+  <int value="-118993417" label="TLS13HardeningForLocalAnchors:disabled"/>
   <int value="-116692797" label="HTTPAuthCommittedInterstitials:enabled"/>
   <int value="-115834377" label="EnableUnifiedMultiDeviceSetup:disabled"/>
   <int value="-114807608" label="TerminalSystemApp:disabled"/>
@@ -37083,6 +37093,7 @@
       label="enable-fullscreen-handwriting-virtual-keyboard:disabled"/>
   <int value="681622885" label="FullscreenExitUI:enabled"/>
   <int value="682549212" label="ash-enable-cursor-motion-blur"/>
+  <int value="683013217" label="AllowPopupsDuringPageUnload:disabled"/>
   <int value="684806628" label="TranslateLanguageByULP:disabled"/>
   <int value="685916283" label="enable-zip-archiver-on-file-manager"/>
   <int value="687838135" label="ThirdPartyDoodles:disabled"/>
@@ -37317,6 +37328,7 @@
   <int value="1022424308" label="SignedExchangeSubresourcePrefetch:enabled"/>
   <int value="1022992701" label="enable-origin-chip-always"/>
   <int value="1024560563" label="EnableFuzzyAppSearch:enabled"/>
+  <int value="1026981579" label="TLS13HardeningForLocalAnchors:enabled"/>
   <int value="1027252926" label="SyncSupportSecondaryAccount:enabled"/>
   <int value="1033148287" label="NTPShortcuts:disabled"/>
   <int value="1033412163" label="OmniboxDisplayTitleForCurrentUrl:enabled"/>
@@ -38105,6 +38117,7 @@
   <int value="2047695652" label="DelegateOverscrollSwipes:enabled"/>
   <int value="2047981703" label="IntentPicker:enabled"/>
   <int value="2049432745" label="VaapiWebPImageDecodeAcceleration:enabled"/>
+  <int value="2050985807" label="AllowPopupsDuringPageUnload:enabled"/>
   <int value="2051403297" label="ShowBluetoothDeviceBattery:disabled"/>
   <int value="2053273256" label="BundledHTTPExchanges:disabled"/>
   <int value="2056572020" label="EnableUsernameCorrection:disabled"/>
@@ -38881,6 +38894,11 @@
   </int>
 </enum>
 
+<enum name="ManagedUserURLRequestPermissionSource">
+  <int value="0" label="MAIN_FRAME">Request was made from main frame</int>
+  <int value="1" label="SUB_FRAME">Request was made from subframe</int>
+</enum>
+
 <enum name="ManagePasswordsReferrer">
   <int value="0" label="Chrome Settings"/>
   <int value="1" label="Manage Passwords Bubble"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index e84b597..dfc66aea 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -6674,6 +6674,16 @@
   </summary>
 </histogram>
 
+<histogram name="Arc.PlayStoreLaunch.TimeDelta" units="ms"
+    expires_after="2021-11-01">
+  <owner>khmel@google.com</owner>
+  <owner>yusukes@google.com</owner>
+  <summary>
+    Elapsed time from the when the user launches the Play Store app and to when
+    the Play Store window is shown to the user.
+  </summary>
+</histogram>
+
 <histogram name="Arc.PlayStoreSearch.QueryTime" units="ms"
     expires_after="2020-03-22">
   <owner>hejq@chromium.org</owner>
@@ -6707,7 +6717,7 @@
   </summary>
 </histogram>
 
-<histogram name="Arc.PlayStoreShown.TimeDelta" units="ms" expires_after="M81">
+<histogram name="Arc.PlayStoreShown.TimeDelta" units="ms" expires_after="M82">
 <!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
 
   <owner>yusukes@google.com</owner>
@@ -6898,6 +6908,42 @@
   <summary>Action of ARC++ Graphics Tracing tool.</summary>
 </histogram>
 
+<histogram name="Arc.UiAvailable.AlreadyProvisioned.TimeDelta" units="ms"
+    expires_after="2021-11-01">
+<!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
+
+  <owner>khmel@google.com</owner>
+  <owner>yusukes@google.com</owner>
+  <summary>
+    Elapsed time from the when ARC++ is started in already provisioned state to
+    when the ARC is available for the user.
+  </summary>
+</histogram>
+
+<histogram name="Arc.UiAvailable.InSessionProvisioning.TimeDelta" units="ms"
+    expires_after="2021-11-01">
+<!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
+
+  <owner>khmel@google.com</owner>
+  <owner>yusukes@google.com</owner>
+  <summary>
+    Elapsed time from the when ARC++ is opted in from the user's session to when
+    the ARC is available for the user.
+  </summary>
+</histogram>
+
+<histogram name="Arc.UiAvailable.OobeProvisioning.TimeDelta" units="ms"
+    expires_after="2021-11-01">
+<!-- Name completed by histogram_suffixes name="ArcUserTypes" -->
+
+  <owner>khmel@google.com</owner>
+  <owner>yusukes@google.com</owner>
+  <summary>
+    Elapsed time from the when ARC++ is opted in from OOBE to when the ARC is
+    available for the user.
+  </summary>
+</histogram>
+
 <histogram name="Arc.UserInteraction" enum="ArcUserInteraction"
     expires_after="2020-03-29">
   <owner>jhorwich@chromium.org</owner>
@@ -6925,7 +6971,8 @@
   </summary>
 </histogram>
 
-<histogram name="ArcAuth.CheckinAttempts" units="attempts" expires_after="M81">
+<histogram name="ArcAuth.CheckinAttempts" units="attempts"
+    expires_after="2021-11-01">
   <owner>elijahtaylor@chromium.org</owner>
   <summary>
     Number of attempts done while waiting for the check-in task to be completed.
@@ -6934,7 +6981,7 @@
   </summary>
 </histogram>
 
-<histogram name="ArcAuth.CheckinTime" units="ms" expires_after="2020-03-08">
+<histogram name="ArcAuth.CheckinTime" units="ms" expires_after="2021-11-01">
   <owner>elijahtaylor@chromium.org</owner>
   <summary>
     Elapsed time waiting for the check-in task to be completed. This is recorded
@@ -6950,7 +6997,7 @@
   </summary>
 </histogram>
 
-<histogram name="ArcAuth.SignInTime" units="ms" expires_after="M77">
+<histogram name="ArcAuth.SignInTime" units="ms" expires_after="2021-11-01">
   <owner>elijahtaylor@chromium.org</owner>
   <summary>Elapsed time waiting for GMS sign-in to complete.</summary>
 </histogram>
@@ -8577,7 +8624,7 @@
 </histogram>
 
 <histogram name="Assistant.ExitPoint" enum="AssistantExitPoint"
-    expires_after="2019-11-19">
+    expires_after="2020-11-19">
   <owner>xiaohuic@chromium.org</owner>
   <owner>meilinw@chromium.org</owner>
   <summary>
@@ -10467,6 +10514,23 @@
   </summary>
 </histogram>
 
+<histogram name="Autofill.BetterAuth.CardUnmaskPreflightCalled"
+    enum="BooleanHit" expires_after="2020-12-15">
+  <owner>jsaul@google.com</owner>
+  <owner>manasverma@google.com</owner>
+  <owner>autofill-auth-team@google.com</owner>
+  <summary>
+    Tracks the number of times Chrome made a GetDetailsForGetRealPan call. A
+    preflight call is only made when card suggestions are shown, and can only
+    happen when the user has server cards and is eligible for WebAuthn.
+
+    As a percentage of the number of times card suggestions are shown, which is
+    tracked under Autofill.FormEvents.CreditCard, this metric provides an
+    estimate for the potential reach for the Autofill Better Auth project.
+    Moreover, this acts as a baseline value for other metrics in this project.
+  </summary>
+</histogram>
+
 <histogram name="Autofill.CanLogUKM" enum="BooleanEnabled" expires_after="M78">
   <owner>dlkumar@google.com</owner>
   <owner>chrome-autofill@google.com</owner>
@@ -13013,6 +13077,17 @@
   </summary>
 </histogram>
 
+<histogram base="true"
+    name="Availability.Prober.DidSucceed.AfterReportedFailure"
+    enum="BooleanSuccess" expires_after="2020-08-01">
+  <owner>robertogden@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    Records the completion status of a probe retry after an externally reported
+    failure.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Availability.Prober.FinalState"
     enum="BooleanSuccess" expires_after="2020-08-01">
   <owner>robertogden@chromium.org</owner>
@@ -21183,6 +21258,17 @@
   </summary>
 </histogram>
 
+<histogram name="Clipboard.RegisterClipboardFormatFailure" units="count"
+    expires_after="2021-01-01">
+  <owner>huangdarwin@chromium.org</owner>
+  <owner>src/ui/base/clipboard/OWNERS</owner>
+  <summary>
+    Counts how often the Windows clipboard fails to register a format. Recorded
+    when RegisterClipbaordFormat fails (returns 0). Failure rates will inform
+    whether we implement error handling. https://crbug.com/1000919
+  </summary>
+</histogram>
+
 <histogram name="Clipboard.X11StoreCopyPasteDuration" units="ms">
   <owner>pkotwicz@chromium.org</owner>
   <summary>
@@ -59170,6 +59256,26 @@
   </summary>
 </histogram>
 
+<histogram name="ManagedUsers.BlockedFrameDepth" units="depth"
+    expires_after="M85">
+  <owner>yilkal@chromium.org</owner>
+  <owner>michaelpg@chromium.org</owner>
+  <summary>
+    The depth of blocked frame in the frame tree. The value is recorded when the
+    renderer frame hosting the blocking page finishes loading.
+  </summary>
+</histogram>
+
+<histogram name="ManagedUsers.BlockedIframeCount" units="iframes"
+    expires_after="M85">
+  <owner>yilkal@chromium.org</owner>
+  <owner>michaelpg@chromium.org</owner>
+  <summary>
+    The number of blocked iframes per unblocked main frame load. The value is
+    recorded when the main frame finishes loading.
+  </summary>
+</histogram>
+
 <histogram name="ManagedUsers.ChromeOS.PasswordChange"
     enum="ManagedUserPasswordChange" expires_after="M77">
   <owner>achuith@chromium.org</owner>
@@ -59227,6 +59333,15 @@
   </summary>
 </histogram>
 
+<histogram name="ManagedUsers.RequestPermissionSource"
+    enum="ManagedUserURLRequestPermissionSource" expires_after="M85">
+  <owner>michaelpg@chromium.org</owner>
+  <owner>yilkal@chromium.org</owner>
+  <summary>
+    The counts of request for permission sent from main frame or sub-frame.
+  </summary>
+</histogram>
+
 <histogram name="ManagedUsers.SafeSitesDelay" units="ms">
   <owner>treib@chromium.org</owner>
   <owner>escordeiro@chromium.org</owner>
@@ -80605,6 +80720,46 @@
   </summary>
 </histogram>
 
+<histogram name="Net.QuicSession.ReceivedSettings.BlockedStreams" units="units"
+    expires_after="2020-10-09">
+  <owner>bnc@chromium.org</owner>
+  <owner>src/net/quic/OWNERS</owner>
+  <summary>
+    The value of the SETTINGS_QPACK_BLOCKED_STREAMS parameter received on an
+    HTTP/3 connection, if any.
+  </summary>
+</histogram>
+
+<histogram name="Net.QuicSession.ReceivedSettings.CountPlusOne" units="units"
+    expires_after="2020-10-09">
+  <owner>bnc@chromium.org</owner>
+  <owner>src/net/quic/OWNERS</owner>
+  <summary>
+    The number of SETTINGS parameters received on an HTTP/3 connection,
+    incremented by one (the SETTINGS frame can be empty).
+  </summary>
+</histogram>
+
+<histogram name="Net.QuicSession.ReceivedSettings.MaxHeaderListSize"
+    units="bytes" expires_after="2020-10-09">
+  <owner>bnc@chromium.org</owner>
+  <owner>src/net/quic/OWNERS</owner>
+  <summary>
+    The value of the SETTINGS_MAX_HEADER_LIST_SIZE parameter received on an
+    HTTP/3 connection, if any.
+  </summary>
+</histogram>
+
+<histogram name="Net.QuicSession.ReceivedSettings.MaxTableCapacity"
+    units="bytes" expires_after="2020-10-09">
+  <owner>bnc@chromium.org</owner>
+  <owner>src/net/quic/OWNERS</owner>
+  <summary>
+    The value of the SETTINGS_QPACK_MAX_TABLE_CAPACITY parameter received on an
+    HTTP/3 connection, if any.
+  </summary>
+</histogram>
+
 <histogram name="Net.QuicSession.RejectHasProof" enum="Boolean"
     expires_after="2018-08-30">
   <owner>rch@chromium.org</owner>
@@ -96538,10 +96693,11 @@
   <summary>
     Only recorded if the page has at least one identified ad frame. Recorded in
     PageLoadMetrics when the page is destroyed. Bytes include all bytes used by
-    the network to load a resource and response body bytes for cached resources.
-    An ad frame consists of the identified ad frame and all of its children
-    (which may also be ads, but are counted as part of the ancestor ad frame).
-    Includes resources that did not finish loading.
+    the network to load a resource and response body bytes for cached resources
+    (from both the HTTP and memory caches). An ad frame consists of the
+    identified ad frame and all of its children (which may also be ads, but are
+    counted as part of the ancestor ad frame). Includes resources that did not
+    finish loading.
   </summary>
 </histogram>
 
@@ -113596,6 +113752,18 @@
   </summary>
 </histogram>
 
+<histogram name="Profile.Menu.OpenedAfterAvatarAnimation" units="ms"
+    expires_after="2020-03-01">
+  <owner>droger@chromium.org</owner>
+  <owner>jkrcal@chromium.org</owner>
+  <summary>
+    When the profile menu is opened, after the identity animation was shown,
+    this records the time since the animation was shown. In the control group
+    for the identity pill experiment, this is still recorded as the time since
+    the animation *would have been* shown.
+  </summary>
+</histogram>
+
 <histogram name="Profile.NetUserCount" enum="ProfileNetUserCount"
     expires_after="2020-02-16">
   <owner>rogerta@chromium.org</owner>
@@ -163366,6 +163534,17 @@
   </summary>
 </histogram>
 
+<histogram name="X11.XInternAtomFailure" units="count"
+    expires_after="2021-01-01">
+  <owner>huangdarwin@chromium.org</owner>
+  <owner>src/ui/base/clipboard/OWNERS</owner>
+  <summary>
+    Counts how often the X11 server fails to register an atom. Recorded when
+    ::XInternAtom fails (returns None). Failure rates will inform whether we
+    implement error handling. https://crbug.com/1000919
+  </summary>
+</histogram>
+
 <histogram name="XHR.Async.PageDismissal" enum="XHRPageDismissalState"
     expires_after="M81">
   <owner>panicker@chromium.org</owner>
@@ -163750,6 +163929,13 @@
       label="Includes all resources loaded by the page."/>
   <suffix name="NonAdFrames.Aggregate.Total"
       label="The size (in KB) of all of the page's resources except for those
+             loaded in ad frames.">
+    <obsolete>
+      Deprecated 09/2019. Replaced with NonAdFrames.Aggregate.Total2.
+    </obsolete>
+  </suffix>
+  <suffix name="NonAdFrames.Aggregate.Total2"
+      label="The size (in KB) of all of the page's resources except for those
              loaded in ad frames."/>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes"/>
   <affected-histogram name="PageLoad.Clients.Ads.NonVisible.Bytes"/>
@@ -163867,7 +164053,12 @@
   <suffix name="Network"
       label="The size (in KB) of all of resources that loaded over the
              network."/>
-  <suffix name="Total" label="The size (in KB) of the resources loaded."/>
+  <suffix name="Total" label="The size (in KB) of the resources loaded.">
+    <obsolete>
+      Deprecated 09/2019. Replaced with Total2.
+    </obsolete>
+  </suffix>
+  <suffix name="Total2" label="The size (in KB) of the resources loaded."/>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate"/>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame"/>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes.FullPage"/>
@@ -163889,18 +164080,46 @@
   <suffix name="PercentAds"
       label="The percentage of bytes loaded from within ad frames."/>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes.FullPage.Network"/>
-  <affected-histogram name="PageLoad.Clients.Ads.Bytes.FullPage.Total"/>
+  <affected-histogram name="PageLoad.Clients.Ads.Bytes.FullPage.Total">
+    <obsolete>
+      Deprecated 09/2019. Replaced with PercentAds2 suffix.
+    </obsolete>
+  </affected-histogram>
   <affected-histogram
       name="PageLoad.Clients.Ads.NonVisible.Bytes.FullPage.Network"/>
   <affected-histogram
-      name="PageLoad.Clients.Ads.NonVisible.Bytes.FullPage.Total"/>
+      name="PageLoad.Clients.Ads.NonVisible.Bytes.FullPage.Total">
+    <obsolete>
+      Deprecated 09/2019. Replaced with PercentAds2 suffix.
+    </obsolete>
+  </affected-histogram>
   <affected-histogram
       name="PageLoad.Clients.Ads.Visible.Bytes.FullPage.Network"/>
-  <affected-histogram name="PageLoad.Clients.Ads.Visible.Bytes.FullPage.Total"/>
+  <affected-histogram name="PageLoad.Clients.Ads.Visible.Bytes.FullPage.Total">
+    <obsolete>
+      Deprecated 09/2019. Replaced with PercentAds2 suffix.
+    </obsolete>
+  </affected-histogram>
+</histogram_suffixes>
+
+<histogram_suffixes name="AdsPageLoadMetricsPercentAds2" separator=".">
+  <suffix name="PercentAds2"
+      label="The percentage of bytes loaded from within ad frames."/>
+  <affected-histogram name="PageLoad.Clients.Ads.Bytes.FullPage.Total2"/>
+  <affected-histogram
+      name="PageLoad.Clients.Ads.NonVisible.Bytes.FullPage.Total2"/>
+  <affected-histogram
+      name="PageLoad.Clients.Ads.Visible.Bytes.FullPage.Total2"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="AdsPageLoadMetricsPercentNetwork" separator=".">
   <suffix name="PercentNetwork"
+      label="The percentage of bytes that were loaded over the network.">
+    <obsolete>
+      Deprecated 09/2019. Replaced with PercentNetwork2.
+    </obsolete>
+  </suffix>
+  <suffix name="PercentNetwork2"
       label="The percentage of bytes that were loaded over the network."/>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate"/>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame"/>
@@ -163917,10 +164136,25 @@
 <histogram_suffixes name="AdsPageLoadMetricsSameOriginBytes" separator=".">
   <suffix name="PercentSameOrigin"
       label="The percentage of bytes loaded from the same origin as the root
+             frame of the page or ad.">
+    <obsolete>
+      Deprecated 09/2019. Replaced with PercentSameOrigin2.
+    </obsolete>
+  </suffix>
+  <suffix name="PercentSameOrigin2"
+      label="The percentage of bytes loaded from the same origin as the root
              frame of the page or ad."/>
   <suffix name="SameOrigin"
-      label="The number of bytes loaded from the same origin as the root
-             frame of the page or ad."/>
+      label="The number of bytes loaded from the same origin as the root frame
+             of the page or ad.">
+    <obsolete>
+      Deprecated 09/2019. Replaced with SameOrigin2.
+    </obsolete>
+  </suffix>
+  <suffix name="SameOrigin2"
+      label="The number of bytes (including those from both the HTTP cache
+             and memory cache) loaded from the same origin as the root frame
+             of the page or ad."/>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame"/>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes.FullPage"/>
   <affected-histogram
@@ -164312,6 +164546,9 @@
   <affected-histogram name="Arc.Provisioning.TimeDelta.Success"/>
   <affected-histogram name="Arc.Reauthorization.Result"/>
   <affected-histogram name="Arc.StateByUserType"/>
+  <affected-histogram name="Arc.UiAvailable.AlreadyProvisioned.TimeDelta"/>
+  <affected-histogram name="Arc.UiAvailable.InSessionProvisioning.TimeDelta"/>
+  <affected-histogram name="Arc.UiAvailable.OobeProvisioning.TimeDelta"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="AsyncDNSPref" separator="_">
@@ -164734,6 +164971,8 @@
       label="Origin check for Litepage previews"/>
   <affected-histogram name="Availability.Prober.CacheEntryAge"/>
   <affected-histogram name="Availability.Prober.DidSucceed"/>
+  <affected-histogram
+      name="Availability.Prober.DidSucceed.AfterReportedFailure"/>
   <affected-histogram name="Availability.Prober.FinalState"/>
   <affected-histogram name="Availability.Prober.NetError"/>
   <affected-histogram name="Availability.Prober.NumAttemptsBeforeSuccess"/>
@@ -165179,7 +165418,11 @@
   <suffix name="App"
       label="Collected from the HTML5 Application Cache instance."/>
   <suffix name="Http" label="Collected from the HTTP Cache instance."/>
-  <suffix name="Media" label="Collected from the Media Cache instance."/>
+  <suffix name="Media" label="Collected from the Media Cache instance.">
+    <obsolete>
+      Noticed unused 2019-10-09
+    </obsolete>
+  </suffix>
   <affected-histogram name="SimpleCache.CacheSizeOnInit"/>
   <affected-histogram name="SimpleCache.CheckCRCResult"/>
   <affected-histogram name="SimpleCache.ConsistencyResult"/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index ea6a6131..f345143 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -115,12 +115,23 @@
     </summary>
   </metric>
   <metric name="Loading.CacheBytes">
+    <obsolete>
+      Deprecated 09/2019. Replaced with Loading.CacheBytes2.
+    </obsolete>
     <summary>
       Bytes loaded from the cache for all resources loaded within the frame.
       This is rounded down to the nearest exponential bucket (with a bucket
       ratio of 1.3).
     </summary>
   </metric>
+  <metric name="Loading.CacheBytes2">
+    <summary>
+      Bytes loaded from the cache for all resources loaded within the frame.
+      This includes bytes loaded from both the HTTP cache and memory cache. This
+      is rounded down to the nearest exponential bucket (with a bucket ratio of
+      1.3).
+    </summary>
+  </metric>
   <metric name="Loading.ImageBytes">
     <summary>
       Network bytes loaded for resources with an image mime type within the
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py
index fbbe384..f77fd1a 100755
--- a/tools/perf/process_perf_results.py
+++ b/tools/perf/process_perf_results.py
@@ -64,6 +64,7 @@
   'media_perftests',
   'net_perftests',
   'passthrough_command_buffer_perftests',
+  'services_perftests',
   'tracing_perftests',
   'validating_command_buffer_perftests',
   'views_perftests',
diff --git a/tools/traffic_annotation/README.md b/tools/traffic_annotation/README.md
index 1b2b431c..2b8c522 100644
--- a/tools/traffic_annotation/README.md
+++ b/tools/traffic_annotation/README.md
@@ -8,13 +8,13 @@
 # Traffic Annotation Auditor
 This is the main executable for all the tests. It runs Traffic Annotation
 Extractor clang tool to check the repository, extract annotations, and perform
-required tests and maintanance. See more details in
+required tests and maintenance. See more details in
 `tools/traffic_annotation/auditor/README.md`.
 
 # Traffic Annotation Extractor
 Traffic Annotation Auditor uses this clang tool (located in
 `tools\clang\traffic_annotation_extractor`) to parse the code and extract
-required data for testing and maintanance.
+required data for testing and maintenance.
 
 # Building the Checkers
 We do not want every developer to have to build clang tool and auditor, and so
@@ -26,7 +26,7 @@
 # Automatic Annotation Tests
 Network traffic annotations are tested in commit queue using
 `tools/traffic_annotation/scripts/check_annotations.py`. This test is currently
-run on Linux and Windows trybots, but may expand in future to other platfroms.
+run on Linux and Windows trybots, but may expand in future to other platforms.
 To perform this test fast enough for a trybot and to avoid spamming the commit
 queue if an unexpected general failure happens (see next item), trybot tests are
 run in error resilient mode and only on the changed files. A more complete test
diff --git a/tools/traffic_annotation/auditor/README.md b/tools/traffic_annotation/auditor/README.md
index 0005e4f..700f09f 100644
--- a/tools/traffic_annotation/auditor/README.md
+++ b/tools/traffic_annotation/auditor/README.md
@@ -1,7 +1,7 @@
 # Network Traffic Annotation Auditor
 This binary runs the clang tool for extraction of Network Traffic Annotations
 from chromium source code, collects and summarizes its outputs, and performs
-tests and maintanance.
+tests and maintenance.
 Please see `docs/network_traffic_annotations.md` for an introduction to network
 traffic annotations.
 
@@ -33,7 +33,7 @@
 Use * as wildcard for zero or more characters when specifying file paths.
 
 Here are the exception types:
-* `all`: Files and paths in this category are excempted from all tests.
+* `all`: Files and paths in this category are exempted from all tests.
 * `missing`: Files and paths in this category can use the
   MISSING_TRAFFIC_ANNOTATION tag.
 * `mutable_tag`: Files and paths in this category can use the
@@ -41,3 +41,5 @@
 * `direct_assignment`: The functions in this category can assign a value
   directly to a MutableNetworkTrafficAnnotationTag. This is controlled to
   avoid assigning arbitrary values to mutable annotations.
+* `test_annotation`: Files and paths in this category can use the
+  TRAFFIC_ANNOTATION_FOR_TESTS tag.
diff --git a/tools/traffic_annotation/auditor/auditor_result.h b/tools/traffic_annotation/auditor/auditor_result.h
index 4b331864f..2fe3bc8 100644
--- a/tools/traffic_annotation/auditor/auditor_result.h
+++ b/tools/traffic_annotation/auditor/auditor_result.h
@@ -12,7 +12,7 @@
  public:
   enum class Type {
     RESULT_OK,               // No error
-    RESULT_IGNORE,           // The item does not require furthure processing.
+    RESULT_IGNORE,           // The item does not require further processing.
     ERROR_FATAL,             // A fatal error that should stop process.
     ERROR_MISSING_TAG_USED,  // A function is called with
                              // MISSING_TRAFFIC_ANNOTATION tag.
@@ -43,7 +43,7 @@
                                    // annotation is not paired with any other
                                    // annotation to be completed.
     ERROR_DIRECT_ASSIGNMENT,       // A value is directly assigned to a mutable
-                                   // annotation or annotation instialized with
+                                   // annotation or annotation initialized with
                                    // list expresssion.
     ERROR_ANNOTATIONS_XML_UPDATE,  // Annotations XML requires update.
     ERROR_TEST_ANNOTATION,         // Annotation for tests is used.
diff --git a/tools/traffic_annotation/auditor/safe_list.txt b/tools/traffic_annotation/auditor/safe_list.txt
index 892cc1d..7367dd5 100644
--- a/tools/traffic_annotation/auditor/safe_list.txt
+++ b/tools/traffic_annotation/auditor/safe_list.txt
@@ -1,5 +1,5 @@
 # This is a comma separated file, specifying the safe list for network traffic
-# anntotation auditor. Please refer to README.md for more details.
+# annotation auditor. Please refer to README.md for more details.
 all,tools/*,*test*,*fuzzer*,*mock*,*fake*
 missing,remoting/host/token_validator_factory_impl.cc
 missing,components/cronet/cronet_url_request.cc
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
index 93b6823..e4c470b 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
@@ -311,7 +311,7 @@
     FILE* options_file,
     bool use_compile_commands) {
   // As the checked out clang tool may be in a directory different from the
-  // default one (third_party/llvm-buid/Release+Asserts/bin), its path and
+  // default one (third_party/llvm-build/Release+Asserts/bin), its path and
   // clang's library folder should be passed to the run_tool.py script.
   fprintf(
       options_file,
@@ -643,7 +643,7 @@
   // Unittests should be all annotated. Although this can be detected using gn,
   // doing that would be very slow. The alternative solution would be to bypass
   // every file including test or unittest, but in this case there might be some
-  // ambiguety in what should be annotated and what not.
+  // ambiguity in what should be annotated and what not.
   if (call.file_path.find("unittest") != std::string::npos)
     return false;
 
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc
index d1f8ac79..f247145 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc
@@ -19,7 +19,7 @@
 
 const char* HELP_TEXT = R"(
 Traffic Annotation Auditor
-Extracts network traffic annotaions from the repository, audits them for errors
+Extracts network traffic annotations from the repository, audits them for errors
 and coverage, produces reports, and updates related files.
 
 Usage: traffic_annotation_auditor [OPTION]... [path_filters]
@@ -67,7 +67,7 @@
   --extractor-backend=[clang_tool,python_script]
                       Optional flag specifying which backend to use for
                       extracting annotation definitions from source code (Clang
-                      Tool or extractor.py). Defaults to "clang_tool".
+                      Tool or extractor.py). Defaults to "python_script".
   path_filters        Optional paths to filter which files the tool is run on.
                       It can also include deleted files names when auditor is
                       run on a partial repository.
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
index 4dbd6c2..935dfcc 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
@@ -286,7 +286,7 @@
                              AuditorException::ExceptionType::TEST_ANNOTATION));
 }
 
-// Tests if annotation instances are corrrectly deserialized.
+// Tests if annotation instances are correctly deserialized.
 TEST_F(TrafficAnnotationAuditorTest, AnnotationDeserialization) {
   struct AnnotationSample {
     std::string file_name;
@@ -340,7 +340,7 @@
   }
 }
 
-// Tests if call instances are corrrectly deserialized.
+// Tests if call instances are correctly deserialized.
 TEST_F(TrafficAnnotationAuditorTest, CallDeserialization) {
   struct CallSample {
     std::string file_name;
@@ -369,7 +369,7 @@
   }
 }
 
-// Tests if call instances are corrrectly deserialized.
+// Tests if call instances are correctly deserialized.
 TEST_F(TrafficAnnotationAuditorTest, AssignmentDeserialization) {
   struct Assignmentample {
     std::string file_name;
diff --git a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
index 5ad4497..83664058 100644
--- a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
+++ b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
@@ -1 +1 @@
-e7c47594d4aeafff709f574183586e7ebc99817a
\ No newline at end of file
+09241cc9dd3f76e7e164799ac5ec909e490cf267
\ No newline at end of file
diff --git a/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1 b/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
index 25f6525..e03983e 100644
--- a/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
+++ b/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
@@ -1 +1 @@
-23b304a9748dc1cf023e4c35e34c2b0a90cc5e95
\ No newline at end of file
+e110771a30480e9676c80fc7963c9f9f408f8af2
\ No newline at end of file
diff --git a/tools/traffic_annotation/sample_traffic_annotation.cc b/tools/traffic_annotation/sample_traffic_annotation.cc
index 21001fa..d35915f7 100644
--- a/tools/traffic_annotation/sample_traffic_annotation.cc
+++ b/tools/traffic_annotation/sample_traffic_annotation.cc
@@ -74,7 +74,7 @@
 
 // Example for Nx1 partial annotations where the partial annotations are defined
 // in PrefetchImage1 and PrefetchImage2, and the completing annotation is
-// defined in GetBitmap. Patial annotations are missing cookies fields and are
+// defined in GetBitmap. Partial annotations are missing cookies fields and are
 // completed in GetBitmap function.
 void PrefetchImage1(const GURL& url) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
@@ -116,7 +116,7 @@
 
 void PrefetchImage2(const GURL& url) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
-      net::DefinePartialNetworkTrafficAnnotation("credenential_avatar",
+      net::DefinePartialNetworkTrafficAnnotation("credential_avatar",
                                                  "bitmap_fetcher",
                                                  R"(
         semantics {
diff --git a/tools/traffic_annotation/scripts/README.md b/tools/traffic_annotation/scripts/README.md
index b7bd344a5..ab53304 100644
--- a/tools/traffic_annotation/scripts/README.md
+++ b/tools/traffic_annotation/scripts/README.md
@@ -21,4 +21,11 @@
 
 # update_annotations_sheet.py
 This script updates the Google sheet that presents all network traffic
-annotations.
\ No newline at end of file
+annotations.
+
+# extractor.py
+Scans through a set of specified C++ files to detect existing traffic
+annotations in code. It uses regex expressions on source files.
+
+# extractor_test.py
+Unit tests for extractor.py.
diff --git a/tools/traffic_annotation/scripts/update_annotations_sheet.py b/tools/traffic_annotation/scripts/update_annotations_sheet.py
index 40450836..16880eb6 100755
--- a/tools/traffic_annotation/scripts/update_annotations_sheet.py
+++ b/tools/traffic_annotation/scripts/update_annotations_sheet.py
@@ -55,7 +55,7 @@
       silent_change_columns: list of str
           List of the columns whose changes are not reported in the stats.
       last_update_column_name: str
-          Header of the colunm that keeps the latest update date.
+          Header of the column that keeps the latest update date.
       credentials_file_path: str
           Absolute path to read/save user credentials.
       client_secret_file_path: str
@@ -378,7 +378,7 @@
         "silent_change_columns:\n"
         "  List of the columns whose changes are not reported in the stats.\n"
         "last_update_column_name:\n"
-        "  Header of the colunm that keeps the latest update date.\n"
+        "  Header of the column that keeps the latest update date.\n"
         "credentials_file_path:\n"
         "  Absolute path of the file that keeps user credentials.\n"
         "client_secret_file_path:\n"
@@ -389,7 +389,7 @@
 
 def main():
   parser = argparse.ArgumentParser(
-      description="Network Traffic Annotations Sheet Updator")
+      description="Network Traffic Annotations Sheet Updater")
   parser.add_argument(
       "--config-file",
       help="Configurations file.")
diff --git a/tools/traffic_annotation/summary/README.md b/tools/traffic_annotation/summary/README.md
index 8cd46e9..eca74820 100644
--- a/tools/traffic_annotation/summary/README.md
+++ b/tools/traffic_annotation/summary/README.md
@@ -17,8 +17,8 @@
 * `os_list`: List of all platforms on which this annotation exists.
     Currently only including `linux` and `windows`.
 * `file_path`: The file path of the annotation.
-* `reserved`: Reserverd annotations (like annotation for test files) have this
-    attribute. If annotation is a reserverd one, it does not have
+* `reserved`: Reserved annotations (like annotation for test files) have this
+    attribute. If annotation is a reserved one, it does not have
   `content_hash_code` and `file_path` attributes.
 * `deprecated`: Once an annotation is removed from the repository, this
     attribute is added to its item with value equal to the deprecation date, and
diff --git a/ui/accessibility/ax_table_info.cc b/ui/accessibility/ax_table_info.cc
index 9e5bd1c..05a1325 100644
--- a/ui/accessibility/ax_table_info.cc
+++ b/ui/accessibility/ax_table_info.cc
@@ -53,7 +53,7 @@
         child->data().role == ax::mojom::Role::kGroup) {
       FindRowsAndThenCells(child, row_nodes, cell_nodes_per_row,
                            caption_node_id);
-    } else if (child->data().role == ax::mojom::Role::kRow) {
+    } else if (IsTableRow(child->data().role)) {
       row_nodes->push_back(child);
       cell_nodes_per_row->push_back(std::vector<AXNode*>());
       FindCellsInRow(child, &cell_nodes_per_row->back());
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index 88272e4..43c9ee7 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -122,7 +122,6 @@
 
   if (layer()->owner() == this)
     layer()->CompleteAllAnimations();
-  layer()->SuppressPaint();
 
   // Let the delegate know we're in the processing of destroying.
   if (delegate_)
@@ -745,10 +744,6 @@
   return host->CaptureSystemKeyEvents(std::move(dom_codes));
 }
 
-void Window::SuppressPaint() {
-  layer()->SuppressPaint();
-}
-
 // {Set,Get,Clear}Property are implemented in class_property.h.
 
 void Window::SetNativeWindowProperty(const char* key, void* value) {
diff --git a/ui/aura/window.h b/ui/aura/window.h
index 8558a5c..6746f3c 100644
--- a/ui/aura/window.h
+++ b/ui/aura/window.h
@@ -382,11 +382,6 @@
   std::unique_ptr<ScopedKeyboardHook> CaptureSystemKeyEvents(
       base::Optional<base::flat_set<ui::DomCode>> codes);
 
-  // Suppresses painting window content by disgarding damaged rect and ignoring
-  // new paint requests. This is a one way operation and there is no way to
-  // reenable painting.
-  void SuppressPaint();
-
   // NativeWidget::[GS]etNativeWindowProperty use strings as keys, and this is
   // difficult to change while retaining compatibility with other platforms.
   // TODO(benrg): Find a better solution.
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc
index 941e2463..ad865f0 100644
--- a/ui/aura/window_unittest.cc
+++ b/ui/aura/window_unittest.cc
@@ -2910,9 +2910,9 @@
 
   delegate.clear_bounds_changed();
 
-  // Suppress paint on the window since it is hidden (should reset the layer's
+  // Suppress paint on the layer since it is hidden (should reset the layer's
   // delegate to NULL)
-  window->SuppressPaint();
+  window->layer()->SuppressPaint();
   EXPECT_EQ(NULL, window->layer()->delegate());
 
   // Animate to a different position.
diff --git a/ui/base/clipboard/clipboard_format_type.h b/ui/base/clipboard/clipboard_format_type.h
index 98c06de..f69b46d 100644
--- a/ui/base/clipboard/clipboard_format_type.h
+++ b/ui/base/clipboard/clipboard_format_type.h
@@ -37,7 +37,10 @@
 
   // Gets the ClipboardFormatType corresponding to an arbitrary format string,
   // registering it with the system if needed. Due to Windows/Linux
-  // limitations, |format_string| must never be controlled by the user.
+  // limitations, please place limits on the amount of GetType calls with unique
+  // |format_string| arguments, when ingesting |format_string| from
+  // untrusted sources, such as renderer processes. In Windows, a failure will
+  // return an invalid format with Deserialize()'ed value of "0".
   static ClipboardFormatType GetType(const std::string& format_string);
 
   // Get format identifiers for various types.
diff --git a/ui/base/clipboard/clipboard_format_type_aura.cc b/ui/base/clipboard/clipboard_format_type_aura.cc
index 848fafd..d67163b 100644
--- a/ui/base/clipboard/clipboard_format_type_aura.cc
+++ b/ui/base/clipboard/clipboard_format_type_aura.cc
@@ -12,10 +12,10 @@
 constexpr char kMimeTypeFilename[] = "chromium/filename";
 }
 
-// TODO(huangdarwin): Investigate ClipboardFormatType becoming a wrapper
-// around an X11 ::Atom. This wasn't possible in the past, because unit tests
-// spawned a new X11 server for each test, meaning Atom numeric values didn't
-// persist across tests.
+// TODO(huangdarwin): Investigate creating a new clipboard_format_type_x11 as a
+// wrapper around an X11 ::Atom. This wasn't possible in the past, because unit
+// tests spawned a new X11 server for each test, meaning Atom numeric values
+// didn't persist across tests.
 ClipboardFormatType::ClipboardFormatType() = default;
 
 ClipboardFormatType::~ClipboardFormatType() = default;
diff --git a/ui/base/clipboard/clipboard_format_type_win.cc b/ui/base/clipboard/clipboard_format_type_win.cc
index 3538eefc..84404d1 100644
--- a/ui/base/clipboard/clipboard_format_type_win.cc
+++ b/ui/base/clipboard/clipboard_format_type_win.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -29,7 +30,17 @@
                                          DWORD tymed)
     : data_{/* .cfFormat */ static_cast<CLIPFORMAT>(native_format),
             /* .ptd */ nullptr, /* .dwAspect */ DVASPECT_CONTENT,
-            /* .lindex */ index, /* .tymed*/ tymed} {}
+            /* .lindex */ index, /* .tymed*/ tymed} {
+  // Log the frequency of invalid formats being input into the constructor.
+  if (!native_format) {
+    static int error_count = 0;
+    ++error_count;
+    // TODO(https://crbug.com/1000919): Evaluate and remove UMA metrics after
+    // enough data is gathered.
+    base::UmaHistogramCounts100("Clipboard.RegisterClipboardFormatFailure",
+                                error_count);
+  }
+}
 
 ClipboardFormatType::~ClipboardFormatType() = default;
 
diff --git a/ui/base/clipboard/clipboard_x11.cc b/ui/base/clipboard/clipboard_x11.cc
index b318617d7..6870873a 100644
--- a/ui/base/clipboard/clipboard_x11.cc
+++ b/ui/base/clipboard/clipboard_x11.cc
@@ -776,11 +776,6 @@
 void ClipboardX11::WriteData(const ClipboardFormatType& format,
                              const char* data_data,
                              size_t data_len) {
-  // We assume that certain mapping types are only written by trusted code.
-  // Therefore we must upkeep their integrity.
-  if (format.Equals(ClipboardFormatType::GetBitmapType()))
-    return;
-
   std::vector<unsigned char> bytes(data_data, data_data + data_len);
   scoped_refptr<base::RefCountedMemory> mem(
       base::RefCountedBytes::TakeVector(&bytes));
diff --git a/ui/base/glib/glib_integers.h b/ui/base/glib/glib_integers.h
index a875ffe..23ced0e 100644
--- a/ui/base/glib/glib_integers.h
+++ b/ui/base/glib/glib_integers.h
@@ -5,6 +5,8 @@
 #ifndef UI_BASE_GLIB_GLIB_INTEGERS_H_
 #define UI_BASE_GLIB_GLIB_INTEGERS_H_
 
+#include <cstdint>
+
 // GLib/GObject/Gtk all use their own integer typedefs. They are copied here
 // for forward declaration reasons so we don't pull in all of glib/gtypes.h
 // when we just need a gpointer.
@@ -17,9 +19,9 @@
 typedef unsigned short gushort;
 typedef unsigned long gulong;
 typedef unsigned int guint;
+typedef double gdouble;
 
-typedef unsigned short guint16;
-typedef unsigned int guint32;
+typedef int64_t gint64;
 
 typedef void* gpointer;
 typedef const void *gconstpointer;
diff --git a/ui/base/ime/chromeos/input_method_util_unittest.cc b/ui/base/ime/chromeos/input_method_util_unittest.cc
index 44fe56a..2e211597 100644
--- a/ui/base/ime/chromeos/input_method_util_unittest.cc
+++ b/ui/base/ime/chromeos/input_method_util_unittest.cc
@@ -157,8 +157,8 @@
   }
   {
     InputMethodDescriptor desc =
-        GetDesc("xkb:es:cat:cat", "es(cat)", "ca", "CAS");
-    EXPECT_EQ(ASCIIToUTF16("CAS"), util_.GetInputMethodShortName(desc));
+        GetDesc("xkb:es:cat:cat", "es(cat)", "ca", "CAT");
+    EXPECT_EQ(ASCIIToUTF16("CAT"), util_.GetInputMethodShortName(desc));
   }
   {
     InputMethodDescriptor desc =
diff --git a/ui/display/manager/display_change_observer.cc b/ui/display/manager/display_change_observer.cc
index 982dd9f..7beb2ca 100644
--- a/ui/display/manager/display_change_observer.cc
+++ b/ui/display/manager/display_change_observer.cc
@@ -45,7 +45,7 @@
 // Update the list of zoom levels whenever a new device scale factor is added
 // here. See zoom level list in /ui/display/manager/display_util.cc
 const DeviceScaleFactorDPIThreshold kThresholdTableForInternal[] = {
-    {320.f, 2.66666f}, {270.0f, 2.25f}, {230.0f, 2.0f}, {220.0f, 1.77777f},
+    {300.f, 2.66666f}, {270.0f, 2.25f}, {230.0f, 2.0f}, {220.0f, 1.77777f},
     {180.0f, 1.6f},    {150.0f, 1.25f}, {0.0f, 1.0f},
 };
 
@@ -306,16 +306,9 @@
                         ? 0
                         : kInchInMm * mode_info->size().width() /
                               snapshot->physical_size().width();
-  constexpr gfx::Size k225DisplaySizeHack(3000, 2000);
-
   if (snapshot->type() == DISPLAY_CONNECTION_TYPE_INTERNAL) {
     new_info.set_native(true);
-    // TODO(oshima): This is a stopgap hack to deal with b/74845106.
-    // Remove this hack when it's resolved.
-    if (mode_info->size() == k225DisplaySizeHack)
-      device_scale_factor = 2.25f;
-    else if (dpi)
-      device_scale_factor = FindDeviceScaleFactor(dpi);
+    device_scale_factor = FindDeviceScaleFactor(dpi);
   } else {
     ManagedDisplayMode mode;
     if (display_manager_->GetSelectedModeForDisplayId(snapshot->display_id(),
diff --git a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
index 9f58268..5b12e94 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -233,6 +233,15 @@
     "//ui/webui/resources/js/cr:ui",
     "//ui/webui/resources/js/cr/ui:dialogs",
   ]
+  externs_list = [ "$externs_path/chrome_extensions.js" ]
+}
+
+js_unittest("file_manager_dialog_base_unittest") {
+  deps = [
+    ":file_manager_dialog_base",
+    "//ui/file_manager/base/js:test_error_reporting",
+    "//ui/webui/resources/js:webui_resource_test",
+  ]
 }
 
 js_library("file_manager_ui") {
@@ -492,6 +501,7 @@
     ":actions_submenu_unittest",
     ":directory_tree_unittest",
     ":file_list_selection_model_unittest",
+    ":file_manager_dialog_base_unittest",
     ":file_table_list_unittest",
     ":file_table_unittest",
     ":file_tap_handler_unittest",
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base.js
index b3953fd..c94caaaa 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base.js
@@ -84,11 +84,11 @@
    * @param {Function=} opt_onHide Called when the dialog is hidden.
    */
   hide(opt_onHide) {
+    FileManagerDialogBase.shown = false;
     super.hide(() => {
       if (opt_onHide) {
         opt_onHide();
       }
-      FileManagerDialogBase.shown = false;
     });
   }
 }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base_unittest.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base_unittest.js
new file mode 100644
index 0000000..9ae8cbf
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base_unittest.js
@@ -0,0 +1,33 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+async function testShowDialogAfterHide(done) {
+  // Polyfill chrome.app.window.current().
+  /** @suppress {duplicate|checkTypes} */
+  chrome.app = {window: {current: () => null}};
+
+  const container =
+      assertInstanceof(document.createElement('div'), HTMLElement);
+
+  function isShown() {
+    return !!container.querySelector('.cr-dialog-container.shown');
+  }
+
+  const dialog = new FileManagerDialogBase(container);
+  // Show the dialog and wait until .shown is set on .cr-dialog-container.
+  // This happens async.
+  dialog.showBlankDialog();
+  await waitUntil(isShown);
+
+  // Call hide, and validate .shown is removed (sync).
+  dialog.hide();
+  assertFalse(isShown());
+
+  // Show the dialog again and ensure that it gets displayed.
+  // Previously some async processing from hide() would stop
+  // the dialog showing again at all if it was called too soon.
+  dialog.showBlankDialog();
+  await waitUntil(isShown);
+  done();
+}
diff --git a/ui/gfx/x/x11_atom_cache.cc b/ui/gfx/x/x11_atom_cache.cc
index 7ba4268..8c6e3a1 100644
--- a/ui/gfx/x/x11_atom_cache.cc
+++ b/ui/gfx/x/x11_atom_cache.cc
@@ -12,6 +12,7 @@
 
 #include "base/logging.h"
 #include "base/memory/singleton.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/stl_util.h"
 
 namespace {
@@ -270,7 +271,16 @@
   if (it != cached_atoms_.end())
     return it->second;
 
+  // XInternAtom returns None on failure. Source:
+  // https://www.x.org/releases/X11R7.5/doc/man/man3/XInternAtom.3.html
   XAtom atom = XInternAtom(xdisplay_, name, False);
+  if (atom == None) {
+    static int error_count = 0;
+    ++error_count;
+    // TODO(https://crbug.com/1000919): Evaluate and remove UMA metrics after
+    // enough data is gathered.
+    base::UmaHistogramCounts100("X11.XInternAtomFailure", error_count);
+  }
   cached_atoms_.emplace(name, atom);
   return atom;
 }
diff --git a/ui/gfx/x/x11_atom_cache.h b/ui/gfx/x/x11_atom_cache.h
index cc97b5a..9d2bc07 100644
--- a/ui/gfx/x/x11_atom_cache.h
+++ b/ui/gfx/x/x11_atom_cache.h
@@ -5,9 +5,9 @@
 #ifndef UI_GFX_X_X11_ATOM_CACHE_H_
 #define UI_GFX_X_X11_ATOM_CACHE_H_
 
+#include <map>
 #include <string>
 
-#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "ui/gfx/gfx_export.h"
 #include "ui/gfx/x/x11_types.h"
@@ -38,11 +38,13 @@
   ~X11AtomCache();
 
   // Returns the pre-interned Atom without having to go to the x server.
+  // On failure, x11::None is returned.
   XAtom GetAtom(const char*) const;
 
   XDisplay* xdisplay_;
 
-  mutable base::flat_map<std::string, XAtom> cached_atoms_;
+  // Using std::map, as it is possible for thousands of atoms to be registered.
+  mutable std::map<std::string, XAtom> cached_atoms_;
 
   DISALLOW_COPY_AND_ASSIGN(X11AtomCache);
 };
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm b/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm
index 5a1d1f2..75e0091 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm
@@ -27,12 +27,8 @@
   if (!widget)
     return nil;
 
-  auto* top_level_widget = widget->GetTopLevelWidget();
-  if (!top_level_widget)
-    return nil;
-
   auto* window_host = NativeWidgetMacNSWindowHost::GetFromNativeWindow(
-      top_level_widget->GetNativeWindow());
+      widget->GetNativeWindow());
   if (!window_host)
     return nil;
 
diff --git a/ui/views/animation/square_ink_drop_ripple.cc b/ui/views/animation/square_ink_drop_ripple.cc
index 1e157b35..ac5c99c 100644
--- a/ui/views/animation/square_ink_drop_ripple.cc
+++ b/ui/views/animation/square_ink_drop_ripple.cc
@@ -146,7 +146,7 @@
                                          const gfx::Point& center_point,
                                          SkColor color,
                                          float visible_opacity)
-    : activated_shape_(ROUNDED_RECT),
+    : activated_shape_(ActivatedShape::kRoundedRect),
       visible_opacity_(visible_opacity),
       large_size_(large_size),
       large_corner_radius_(large_corner_radius),
@@ -542,10 +542,10 @@
 void SquareInkDropRipple::GetActivatedTargetTransforms(
     InkDropTransforms* transforms_out) const {
   switch (activated_shape_) {
-    case CIRCLE:
+    case ActivatedShape::kCircle:
       CalculateCircleTransforms(small_size_, transforms_out);
       break;
-    case ROUNDED_RECT:
+    case ActivatedShape::kRoundedRect:
       CalculateRectTransforms(small_size_, small_corner_radius_,
                               transforms_out);
       break;
@@ -555,10 +555,10 @@
 void SquareInkDropRipple::GetDeactivatedTargetTransforms(
     InkDropTransforms* transforms_out) const {
   switch (activated_shape_) {
-    case CIRCLE:
+    case ActivatedShape::kCircle:
       CalculateCircleTransforms(large_size_, transforms_out);
       break;
-    case ROUNDED_RECT:
+    case ActivatedShape::kRoundedRect:
       CalculateRectTransforms(large_size_, small_corner_radius_,
                               transforms_out);
       break;
diff --git a/ui/views/animation/square_ink_drop_ripple.h b/ui/views/animation/square_ink_drop_ripple.h
index 8b34df8..af7a1b0 100644
--- a/ui/views/animation/square_ink_drop_ripple.h
+++ b/ui/views/animation/square_ink_drop_ripple.h
@@ -51,7 +51,7 @@
 class VIEWS_EXPORT SquareInkDropRipple : public InkDropRipple {
  public:
   // The shape to use for the ACTIVATED/DEACTIVATED states.
-  enum ActivatedShape { CIRCLE, ROUNDED_RECT };
+  enum class ActivatedShape { kCircle, kRoundedRect };
 
   SquareInkDropRipple(const gfx::Size& large_size,
                       int large_corner_radius,
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc
index dd05976..b8a6fb5 100644
--- a/ui/views/controls/button/label_button.cc
+++ b/ui/views/controls/button/label_button.cc
@@ -66,7 +66,7 @@
   UpdateImage();
 }
 
-base::string16 LabelButton::GetText() const {
+const base::string16& LabelButton::GetText() const {
   return label_->GetText();
 }
 
diff --git a/ui/views/controls/button/label_button.h b/ui/views/controls/button/label_button.h
index cac6b57..1358e05 100644
--- a/ui/views/controls/button/label_button.h
+++ b/ui/views/controls/button/label_button.h
@@ -45,7 +45,7 @@
   void SetImage(ButtonState for_state, const gfx::ImageSkia& image);
 
   // Gets or sets the text shown on the button.
-  base::string16 GetText() const;
+  const base::string16& GetText() const;
   virtual void SetText(const base::string16& text);
 
   // Makes the button report its preferred size without the label. This lets
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 3ef62bbe..276db1fb2 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -2407,44 +2407,61 @@
         y = anchor_bounds.bottom() - border_and_shadow_insets.top() +
             menu_config.touchable_anchor_offset;
       }
-    } else if (state_.anchor == MenuAnchorPosition::kBubbleLeft) {
-      // Align the right of the menu with the left of the anchor, and the top of
-      // the menu with the top of the anchor.
-      x = anchor_bounds.x() - menu_size.width() +
-          border_and_shadow_insets.right() -
-          menu_config.touchable_anchor_offset;
-      y = anchor_bounds.y() - border_and_shadow_insets.top();
-      // Align the left of the menu with the right of the anchor.
-      if (x < monitor_bounds.x()) {
-        x = anchor_bounds.right() - border_and_shadow_insets.left() +
-            menu_config.touchable_anchor_offset;
-      }
-      // Prefer aligning the bottom of the menu to the bottom of the anchor.
-      if (y + menu_size.height() > monitor_bounds.bottom()) {
-        y = anchor_bounds.bottom() - menu_size.height() +
-            border_and_shadow_insets.bottom();
-        // For some very tall menus, this may still be off screen.
-        if (y < monitor_bounds.y())
-          y = monitor_bounds.y();
-      }
-    } else if (state_.anchor == MenuAnchorPosition::kBubbleRight) {
-      // Align the left of the menu with the right of the anchor, and the top of
-      // the menu with the top of the anchor.
-      x = anchor_bounds.right() - border_and_shadow_insets.left() +
-          menu_config.touchable_anchor_offset;
-      y = anchor_bounds.y() - border_and_shadow_insets.top();
-      if (x + menu_size.width() > monitor_bounds.right()) {
-        // Align the right of the menu with the left of the anchor.
+    } else if (state_.anchor == MenuAnchorPosition::kBubbleLeft ||
+               state_.anchor == MenuAnchorPosition::kBubbleRight) {
+      if (state_.anchor == MenuAnchorPosition::kBubbleLeft) {
+        // Align the right of the menu with the left of the anchor, and the top
+        // of the menu with the top of the anchor.
         x = anchor_bounds.x() - menu_size.width() +
             border_and_shadow_insets.right() -
             menu_config.touchable_anchor_offset;
+        // Align the left of the menu with the right of the anchor.
+        if (x < monitor_bounds.x()) {
+          x = anchor_bounds.right() - border_and_shadow_insets.left() +
+              menu_config.touchable_anchor_offset;
+        }
+      } else {
+        // Align the left of the menu with the right of the anchor, and the top
+        // of the menu with the top of the anchor.
+        x = anchor_bounds.right() - border_and_shadow_insets.left() +
+            menu_config.touchable_anchor_offset;
+        if (x + menu_size.width() > monitor_bounds.right()) {
+          // Align the right of the menu with the left of the anchor.
+          x = anchor_bounds.x() - menu_size.width() +
+              border_and_shadow_insets.right() -
+              menu_config.touchable_anchor_offset;
+        }
       }
-      if (y + menu_size.height() > monitor_bounds.bottom()) {
-        // Align the bottom of the menu with the bottom of the anchor.
-        y = anchor_bounds.bottom() - menu_size.height() +
-            border_and_shadow_insets.bottom();
+
+      const int y_below = anchor_bounds.y() - border_and_shadow_insets.top();
+      const int y_above = anchor_bounds.bottom() - menu_size.height() +
+                          border_and_shadow_insets.bottom();
+      if (y_below + menu_size.height() <= monitor_bounds.bottom()) {
+        // Show below the anchor. Align the top of the menu with the top of the
+        // anchor.
+        y = y_below;
+      } else if (y_above >= monitor_bounds.y()) {
+        // No room below, but there is room above. Show above the anchor. Align
+        // the bottom of the menu with the bottom of the anchor.
+        y = y_above;
+      } else {
+        // No room above or below. Show as low as possible. Align the bottom of
+        // the menu with the bottom of the screen.
+        y = monitor_bounds.bottom() - menu_size.height();
       }
     }
+    // The above adjustments may have shifted a large menu off the screen.
+    // Clamp the menu origin to the valid range.
+    const int x_min = monitor_bounds.x() - border_and_shadow_insets.left();
+    const int x_max = monitor_bounds.right() - menu_size.width() +
+                      border_and_shadow_insets.right();
+    const int y_min = monitor_bounds.y() - border_and_shadow_insets.top();
+    const int y_max = monitor_bounds.bottom() - menu_size.height() +
+                      border_and_shadow_insets.bottom();
+    DCHECK_LE(x_min, x_max);
+    DCHECK_LE(y_min, y_max);
+    x = base::ClampToRange(x, x_min, x_max);
+    y = base::ClampToRange(y, y_min, y_max);
   } else {
     if (!use_touchable_layout_) {
       NOTIMPLEMENTED()
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc
index 936a5d2..d3d0855 100644
--- a/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -560,6 +560,62 @@
     EXPECT_TRUE(options.monitor_bounds.Contains(final_bounds));
   }
 
+  void TestMenuFitsOnSmallScreen(MenuAnchorPosition menu_anchor_position,
+                                 const gfx::Rect& monitor_bounds) {
+    SCOPED_TRACE(base::StringPrintf(
+        "MenuAnchorPosition: %d, monitor_bounds: @%s\n", menu_anchor_position,
+        monitor_bounds.ToString().c_str()));
+    MenuBoundsOptions options;
+    options.menu_anchor = menu_anchor_position;
+    options.monitor_bounds = monitor_bounds;
+    options.menu_size = monitor_bounds.size();
+    options.menu_size.Enlarge(100, 100);
+    const gfx::Size anchor_size(0, 0);
+
+    // Adjust the final bounds to not include the shadow and border.
+    const gfx::Insets border_and_shadow_insets =
+        BubbleBorder::GetBorderAndShadowInsets(
+            MenuConfig::instance().touchable_menu_shadow_elevation);
+
+    options.anchor_bounds = gfx::Rect(monitor_bounds.origin(), anchor_size);
+    gfx::Rect final_bounds = CalculateBubbleMenuBounds(options);
+    final_bounds.Inset(border_and_shadow_insets);
+    EXPECT_TRUE(options.monitor_bounds.Contains(final_bounds))
+        << options.monitor_bounds.ToString() << " does not contain "
+        << final_bounds.ToString();
+
+    options.anchor_bounds =
+        gfx::Rect(monitor_bounds.bottom_left(), anchor_size);
+    final_bounds = CalculateBubbleMenuBounds(options);
+    final_bounds.Inset(border_and_shadow_insets);
+    EXPECT_TRUE(options.monitor_bounds.Contains(final_bounds))
+        << options.monitor_bounds.ToString() << " does not contain "
+        << final_bounds.ToString();
+
+    options.anchor_bounds =
+        gfx::Rect(monitor_bounds.bottom_right(), anchor_size);
+    final_bounds = CalculateBubbleMenuBounds(options);
+    final_bounds.Inset(border_and_shadow_insets);
+    EXPECT_TRUE(options.monitor_bounds.Contains(final_bounds))
+        << options.monitor_bounds.ToString() << " does not contain "
+        << final_bounds.ToString();
+
+    options.anchor_bounds = gfx::Rect(monitor_bounds.top_right(), anchor_size);
+    final_bounds = CalculateBubbleMenuBounds(options);
+    final_bounds.Inset(border_and_shadow_insets);
+    EXPECT_TRUE(options.monitor_bounds.Contains(final_bounds))
+        << options.monitor_bounds.ToString() << " does not contain "
+        << final_bounds.ToString();
+
+    options.anchor_bounds =
+        gfx::Rect(monitor_bounds.CenterPoint(), anchor_size);
+    final_bounds = CalculateBubbleMenuBounds(options);
+    final_bounds.Inset(border_and_shadow_insets);
+    EXPECT_TRUE(options.monitor_bounds.Contains(final_bounds))
+        << options.monitor_bounds.ToString() << " does not contain "
+        << final_bounds.ToString();
+  }
+
   void TestSubmenuFitsOnScreen(MenuItemView* item,
                                const gfx::Rect& monitor_bounds,
                                const gfx::Rect& parent_bounds) {
@@ -1855,6 +1911,24 @@
     }
 }
 
+// Test that menus fit a small screen.
+TEST_P(MenuControllerTest, TestMenuFitsOnSmallScreen) {
+  const int display_size = 500;
+
+  // Simulate multiple display layouts.
+  for (int x = -1; x <= 1; x++)
+    for (int y = -1; y <= 1; y++) {
+      const gfx::Rect monitor_bounds(x * display_size, y * display_size,
+                                     display_size, display_size);
+      TestMenuFitsOnSmallScreen(MenuAnchorPosition::kBubbleAbove,
+                                monitor_bounds);
+      TestMenuFitsOnSmallScreen(MenuAnchorPosition::kBubbleLeft,
+                                monitor_bounds);
+      TestMenuFitsOnSmallScreen(MenuAnchorPosition::kBubbleRight,
+                                monitor_bounds);
+    }
+}
+
 // Test that submenus are displayed within the screen bounds on smaller screens.
 TEST_P(MenuControllerTest, TestSubmenuFitsOnScreen) {
   menu_controller()->set_use_touchable_layout(true);
diff --git a/ui/views/linux_ui/linux_ui.h b/ui/views/linux_ui/linux_ui.h
index 9f89eb2..0e7b7ea 100644
--- a/ui/views/linux_ui/linux_ui.h
+++ b/ui/views/linux_ui/linux_ui.h
@@ -119,11 +119,6 @@
   // object by default.
   virtual bool GetDefaultUsesSystemTheme() const = 0;
 
-  // Sets visual properties in the desktop environment related to download
-  // progress, if available.
-  virtual void SetDownloadCount(int count) const = 0;
-  virtual void SetProgressFraction(float percentage) const = 0;
-
   // Returns the icon for a given content type from the icon theme.
   // TODO(davidben): Add an observer for the theme changing, so we can drop the
   // caches.
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index efdf0d81..8fc1b29 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -781,12 +781,8 @@
 }
 
 void DesktopNativeWidgetAura::Close() {
-  if (!content_window_)
-    return;
-
-  content_window_->SuppressPaint();
-
-  desktop_window_tree_host_->Close();
+  if (content_window_)
+    desktop_window_tree_host_->Close();
 }
 
 void DesktopNativeWidgetAura::CloseNow() {
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index e1c2c17..894b80a 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -536,7 +536,6 @@
   DCHECK(window_ ||
          ownership_ == Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET);
   if (window_) {
-    window_->SuppressPaint();
     Hide();
     window_->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
   }
diff --git a/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html b/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html
index edf2296..40fef17 100644
--- a/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html
+++ b/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html
@@ -16,6 +16,10 @@
         --cr-input-error-display: none;
       }
 
+      :host([opened_]) cr-input {
+        --cr-input-border-radius: 4px 4px 0 0;
+      }
+
       iron-dropdown,
       cr-input {
         /* 472px is the max width of the input field for a dialog. */
@@ -32,6 +36,7 @@
 
       iron-dropdown [slot='dropdown-content'] {
         background-color: white;
+        border-radius: 0 0 4px 4px;
         box-shadow: 0 2px 6px var(--paper-grey-500);
         min-width: 128px;
         padding: 8px 0;
@@ -141,7 +146,7 @@
         </div>
         <div id="dropdown-box">
           <iron-dropdown horizontal-align="left" vertical-align="top"
-              vertical-offset="4" no-cancel-on-outside-click
+              vertical-offset="0" no-cancel-on-outside-click
               no-cancel-on-esc-key>
             <div slot="dropdown-content">
               <div id="loading-box" hidden="[[!showLoading]]">
diff --git a/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js b/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js
index ce10ca6..4fdaf01 100644
--- a/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js
+++ b/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js
@@ -80,6 +80,17 @@
 
     /** @private {boolean} */
     dropdownRefitPending_: Boolean,
+
+    /**
+     * Whether the dropdown is currently open. Should only be used by CSS
+     * privately.
+     * @private {boolean}
+     */
+    opened_: {
+      type: Boolean,
+      value: false,
+      reflectToAttribute: true,
+    },
   },
 
   listeners: {
@@ -112,6 +123,18 @@
     }
   },
 
+  /** @private */
+  openDropdown_: function() {
+    this.$$('iron-dropdown').open();
+    this.opened_ = true;
+  },
+
+  /** @private */
+  closeDropdown_: function() {
+    this.$$('iron-dropdown').close();
+    this.opened_ = false;
+  },
+
   /**
    * @param {!Array<string>} oldValue
    * @param {!Array<string>} newValue
@@ -129,7 +152,7 @@
     if (this.readonly) {
       return;
     }
-    this.$$('iron-dropdown').open();
+    this.openDropdown_();
   },
 
   /**
@@ -177,11 +200,11 @@
       event.preventDefault();
     } else if (paths.includes(searchInput)) {
       // A click on the search input should open the dropdown.
-      dropdown.open();
+      this.openDropdown_();
     } else {
       // A click outside either the search input or dropdown should close the
       // dropdown. Implicitly, the search input has lost focus at this point.
-      dropdown.close();
+      this.closeDropdown_();
     }
   },
 
@@ -202,7 +225,7 @@
       case 'Tab':
         // Pressing tab will cause the input field to lose focus. Since the
         // dropdown visibility is tied to focus, close the dropdown.
-        this.$$('iron-dropdown').close();
+        this.closeDropdown_();
         break;
       case 'ArrowUp':
       case 'ArrowDown': {
@@ -223,7 +246,7 @@
         this.value =
             dropdown.querySelector('dom-repeat').modelForElement(selected).item;
         this.searchTerm_ = '';
-        dropdown.close();
+        this.closeDropdown_();
         // Stop the default submit action.
         event.preventDefault();
         break;
@@ -290,7 +313,7 @@
     // closed when the user makes a selection using the mouse or keyboard.
     // However, focus remains on the input field. If the user makes a further
     // change, then the dropdown should be shown.
-    this.$$('iron-dropdown').open();
+    this.openDropdown_();
 
     // iron-dropdown sets its max-height when it is opened. If the current value
     // results in no filtered items in the drop down list, the iron-dropdown
@@ -307,7 +330,7 @@
    * @private
    */
   onSelect_: function(event) {
-    this.$$('iron-dropdown').close();
+    this.closeDropdown_();
 
     this.value = event.model.item;
     this.searchTerm_ = '';
diff --git a/weblayer/browser/content_view_render_view.cc b/weblayer/browser/content_view_render_view.cc
index 2a58ab7..b3ee0f0c 100644
--- a/weblayer/browser/content_view_render_view.cc
+++ b/weblayer/browser/content_view_render_view.cc
@@ -87,8 +87,7 @@
 
 void ContentViewRenderView::SurfaceDestroyed(JNIEnv* env,
                                              jboolean cache_back_buffer) {
-  evict_back_buffer_on_next_swap_ = cache_back_buffer;
-  if (evict_back_buffer_on_next_swap_)
+  if (cache_back_buffer)
     compositor_->CacheBackBufferForCurrentSurface();
   compositor_->SetSurface(nullptr, false);
 }
@@ -116,13 +115,15 @@
 
 void ContentViewRenderView::DidSwapFrame(int pending_frames) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  Java_ContentViewRenderView_didSwapFrame(env, java_obj_);
-  if (evict_back_buffer_on_next_swap_) {
-    compositor_->EvictCachedBackBuffer();
-    evict_back_buffer_on_next_swap_ = false;
+  if (Java_ContentViewRenderView_didSwapFrame(env, java_obj_)) {
+    compositor_->SetNeedsRedraw();
   }
 }
 
+void ContentViewRenderView::EvictCachedSurface(JNIEnv* env) {
+  compositor_->EvictCachedBackBuffer();
+}
+
 void ContentViewRenderView::InitCompositor() {
   if (compositor_)
     return;
diff --git a/weblayer/browser/content_view_render_view.h b/weblayer/browser/content_view_render_view.h
index 2b1c73e..0c2fb82 100644
--- a/weblayer/browser/content_view_render_view.h
+++ b/weblayer/browser/content_view_render_view.h
@@ -53,6 +53,7 @@
                       jint width,
                       jint height,
                       const base::android::JavaParamRef<jobject>& surface);
+  void EvictCachedSurface(JNIEnv* env);
   base::android::ScopedJavaLocalRef<jobject> GetResourceManager(JNIEnv* env);
 
   // CompositorClient implementation
@@ -74,8 +75,6 @@
   scoped_refptr<cc::Layer> root_container_layer_;
   scoped_refptr<cc::Layer> web_contents_layer_;
 
-  bool evict_back_buffer_on_next_swap_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(ContentViewRenderView);
 };
 
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java b/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java
index 0f289dc..247561b 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java
@@ -12,6 +12,7 @@
 import android.view.SurfaceView;
 import android.view.TextureView;
 import android.view.View;
+import android.view.ViewGroup;
 import android.webkit.ValueCallback;
 import android.widget.FrameLayout;
 
@@ -35,19 +36,7 @@
  * the chromium compositor. Note it can be used to display only one WebContents.
  * This allows switching between SurfaceView and TextureView as the source of
  * the Surface used by chromium compositor, and attempts to make the switch
- * visually seamless. The rough steps for a switch are:
- * 1) Allocate new view, and insert it into view hierarchy below the existing
- *    view, so it is not yet showing.
- * 2) When Surface is allocated by new View, swap chromium compositor to the
- *    new Surface. Note at this point the existing view should is still visible.
- * 3) After chromium compositor swaps a frame in the new surface, detach the
- *    existing view.
- * Here are some more details.
- * * New view is added at index 0, ie below all other children.
- * * SurfaceView that uses SurfaceControl will need to retain the underlying
- *   EGLSurface to avoid desotrying the Surface.
- * * Use postOnAnimation to manipulate view tree as it is not safe to modify
- *   the view tree inside layout or draw.
+ * visually seamless.
  */
 @JNINamespace("weblayer")
 public class ContentViewRenderView extends FrameLayout {
@@ -62,7 +51,6 @@
     // This is the mode that last supplied the Surface to the compositor.
     // This should generally be equal to |mRequested| except during transitions.
     private SurfaceData mCurrent;
-    private final ArrayList<SurfaceData> mMarkedForDestroySurfaces = new ArrayList<>();
 
     // The native side of this object.
     private long mNativeContentViewRenderView;
@@ -100,8 +88,8 @@
                     || mSurfaceData == ContentViewRenderView.this.mCurrent;
             if (ContentViewRenderView.this.mCurrent != null
                     && ContentViewRenderView.this.mCurrent != mSurfaceData) {
-                ContentViewRenderView.this.mCurrent.markForDestroy(
-                        mMarkedForDestroySurfaces, true /* hasNextSurface */);
+                ContentViewRenderView.this.mCurrent.markForDestroy(true /* hasNextSurface */);
+                mSurfaceData.setSurfaceDataNeedsDestroy(ContentViewRenderView.this.mCurrent);
             }
             ContentViewRenderView.this.mCurrent = mSurfaceData;
             ContentViewRenderViewJni.get().surfaceCreated(mNativeContentViewRenderView);
@@ -132,18 +120,56 @@
     // Abstract differences between SurfaceView and TextureView behind this class.
     // Also responsible for holding and calling callbacks.
     private static class SurfaceData implements SurfaceEventListener {
+        private class TextureViewWithInvalidate extends TextureView {
+            public TextureViewWithInvalidate(Context context) {
+                super(context);
+            }
+
+            @Override
+            public void invalidate() {
+                // TextureView is invalidated when it receives a new frame from its SurfaceTexture.
+                // This is a safe place to indicate that this TextureView now has content and is
+                // ready to be shown.
+                super.invalidate();
+                destroyPreviousData();
+            }
+        }
+
         @Mode
         private final int mMode;
         private final SurfaceEventListener mListener;
         private final FrameLayout mParent;
+        private final Runnable mEvict;
 
-        private boolean mCreated;
+        private boolean mRanCallbacks;
         private boolean mMarkedForDestroy;
+        private boolean mCachedSurfaceNeedsEviction;
 
         private boolean mNeedsOnSurfaceDestroyed;
 
+        // During transitioning between two SurfaceData, there is a complicated series of calls to
+        // avoid visual artifacts.
+        // 1) Allocate new SurfaceData, and insert it into view hierarchy below the existing
+        //    SurfaceData, so it is not yet showing.
+        // 2) When Surface is allocated by new View, swap chromium compositor to the
+        //    new Surface. |markForDestroy| is called on the previous SurfaceData, and the two
+        //    SurfaceDatas are linked through these two variables.
+        //    Note at this point the existing view is still visible.
+        // 3) Wait until new SurfaceData decides that it has content and is ready to be shown
+        //    * For TextureView, wait until TextureView.invalidate is called
+        //    * For SurfaceView, wait for two swaps from the chromium compositor
+        // 4) New SurfaceData calls |destroy| on previous SurfaceData.
+        //    * For TextureView, it is simply detached immediately from the view tree
+        //    * For SurfaceView, to avoid flicker, move it to the back first before and wait
+        //      two frames before detaching.
+        // 5) Previous SurfaceData runs callbacks on the new SurfaceData to signal the completion
+        //    of the transition.
+        private SurfaceData mPrevSurfaceDataNeedsDestroy;
+        private SurfaceData mNextSurfaceDataNeedsRunCallback;
+
         private final SurfaceHolderCallback mSurfaceCallback;
         private final SurfaceView mSurfaceView;
+        private int mNumSurfaceViewSwapsUntilVisible;
 
         private final TextureView mTextureView;
         private final TextureViewSurfaceTextureListener mSurfaceTextureListener;
@@ -151,10 +177,11 @@
         private final ArrayList<ValueCallback<Boolean>> mModeCallbacks = new ArrayList<>();
 
         public SurfaceData(@Mode int mode, FrameLayout parent, SurfaceEventListener listener,
-                int backgroundColor) {
+                int backgroundColor, Runnable evict) {
             mMode = mode;
             mListener = listener;
             mParent = parent;
+            mEvict = evict;
             if (mode == MODE_SURFACE_VIEW) {
                 mSurfaceView = new SurfaceView(parent.getContext());
                 mSurfaceView.setZOrderMediaOverlay(true);
@@ -167,7 +194,7 @@
                 mTextureView = null;
                 mSurfaceTextureListener = null;
             } else if (mode == MODE_TEXTURE_VIEW) {
-                mTextureView = new TextureView(parent.getContext());
+                mTextureView = new TextureViewWithInvalidate(parent.getContext());
                 mSurfaceTextureListener = new TextureViewSurfaceTextureListener(this);
                 mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
                 mTextureView.setVisibility(VISIBLE);
@@ -178,6 +205,7 @@
                 throw new RuntimeException("Illegal mode: " + mode);
             }
 
+            // This postOnAnimation is to avoid manipulating the view tree inside layout or draw.
             parent.postOnAnimation(() -> {
                 if (mMarkedForDestroy) return;
                 View view = (mMode == MODE_SURFACE_VIEW) ? mSurfaceView : mTextureView;
@@ -191,6 +219,13 @@
             });
         }
 
+        public void setSurfaceDataNeedsDestroy(SurfaceData surfaceData) {
+            assert !mMarkedForDestroy;
+            assert mPrevSurfaceDataNeedsDestroy == null;
+            mPrevSurfaceDataNeedsDestroy = surfaceData;
+            mPrevSurfaceDataNeedsDestroy.mNextSurfaceDataNeedsRunCallback = this;
+        }
+
         public @Mode int getMode() {
             return mMode;
         }
@@ -198,17 +233,21 @@
         public void addCallback(ValueCallback<Boolean> callback) {
             assert !mMarkedForDestroy;
             mModeCallbacks.add(callback);
-            if (mCreated) runCallbacks();
+            if (mRanCallbacks) runCallbacks();
         }
 
         // Tearing down is separated into markForDestroy and destroy. After markForDestroy
         // this class will is guaranteed to not issue any calls to its SurfaceEventListener.
-        public void markForDestroy(ArrayList<SurfaceData> pendingDestroy, boolean hasNextSurface) {
+        public void markForDestroy(boolean hasNextSurface) {
             if (mMarkedForDestroy) return;
             mMarkedForDestroy = true;
 
             if (mNeedsOnSurfaceDestroyed) {
-                mListener.surfaceDestroyed(hasNextSurface && mMode == MODE_SURFACE_VIEW);
+                // SurfaceView being used with SurfaceControl need to cache the back buffer
+                // (EGLSurface). Otherwise the surface is destroyed immediate before the
+                // SurfaceView is detached.
+                mCachedSurfaceNeedsEviction = hasNextSurface && mMode == MODE_SURFACE_VIEW;
+                mListener.surfaceDestroyed(mCachedSurfaceNeedsEviction);
                 mNeedsOnSurfaceDestroyed = false;
             }
 
@@ -219,25 +258,54 @@
             } else {
                 assert false;
             }
-
-            pendingDestroy.add(this);
         }
 
         // Remove view from parent hierarchy.
         public void destroy() {
             assert mMarkedForDestroy;
+            runCallbacks();
+            // This postOnAnimation is to avoid manipulating the view tree inside layout or draw.
             mParent.postOnAnimation(() -> {
                 if (mMode == MODE_SURFACE_VIEW) {
-                    mParent.removeView(mSurfaceView);
+                    // Detaching a SurfaceView causes a flicker because the SurfaceView tears down
+                    // the Surface in SurfaceFlinger before removing its hole in the view tree.
+                    // This is a complicated heuristics to avoid this. It first moves the
+                    // SurfaceView behind the new View. Then wait two frames before detaching
+                    // the SurfaceView. Waiting for a single frame still causes flickers on
+                    // high end devices like Pixel 3.
+                    moveChildToBackWithoutDetach(mParent, mSurfaceView);
+                    mParent.postOnAnimation(() -> mParent.postOnAnimation(() -> {
+                        mParent.removeView(mSurfaceView);
+                        mParent.invalidate();
+                        if (mCachedSurfaceNeedsEviction) {
+                            mEvict.run();
+                            mCachedSurfaceNeedsEviction = false;
+                        }
+                        runCallbackOnNextSurfaceData();
+                    }));
                 } else if (mMode == MODE_TEXTURE_VIEW) {
                     mParent.removeView(mTextureView);
+                    runCallbackOnNextSurfaceData();
                 } else {
                     assert false;
                 }
-                runCallbacks();
             });
         }
 
+        private static void moveChildToBackWithoutDetach(ViewGroup parent, View child) {
+            final int numberOfChildren = parent.getChildCount();
+            final int childIndex = parent.indexOfChild(child);
+            if (childIndex <= 0) return;
+            for (int i = 0; i < childIndex; ++i) {
+                parent.bringChildToFront(parent.getChildAt(0));
+            }
+            assert parent.indexOfChild(child) == 0;
+            for (int i = 0; i < numberOfChildren - childIndex - 1; ++i) {
+                parent.bringChildToFront(parent.getChildAt(1));
+            }
+            parent.invalidate();
+        }
+
         public void setBackgroundColor(int color) {
             assert !mMarkedForDestroy;
             if (mMode == MODE_SURFACE_VIEW) {
@@ -245,7 +313,8 @@
             }
         }
 
-        public void didSwapFrame() {
+        /** @return true if should keep swapping frames */
+        public boolean didSwapFrame() {
             if (mSurfaceView != null && mSurfaceView.getBackground() != null) {
                 mSurfaceView.post(new Runnable() {
                     @Override
@@ -254,17 +323,32 @@
                     }
                 });
             }
+            if (mMode == MODE_SURFACE_VIEW) {
+                // We have no reliable signal for when to show a SurfaceView. This is a heuristic
+                // (used by chrome as well) is to wait for 2 swaps from the chromium comopsitor
+                // as a signal that the SurfaceView has content and is ready to be displayed.
+                if (mNumSurfaceViewSwapsUntilVisible > 0) {
+                    mNumSurfaceViewSwapsUntilVisible--;
+                }
+                if (mNumSurfaceViewSwapsUntilVisible == 0) {
+                    destroyPreviousData();
+                }
+                return mNumSurfaceViewSwapsUntilVisible > 0;
+            }
+            return false;
+        }
+
+        private void destroyPreviousData() {
+            if (mPrevSurfaceDataNeedsDestroy != null) {
+                mPrevSurfaceDataNeedsDestroy.destroy();
+                mPrevSurfaceDataNeedsDestroy = null;
+            }
         }
 
         @Override
         public void surfaceCreated() {
             if (mMarkedForDestroy) return;
 
-            if (!mCreated) {
-                mCreated = true;
-                runCallbacks();
-            }
-
             // On pre-M Android, layers start in the hidden state until a relayout happens.
             // There is a bug that manifests itself when entering overlay mode on pre-M devices,
             // where a relayout never happens. This bug is out of Chromium's control, but can be
@@ -274,6 +358,11 @@
                 mSurfaceView.setVisibility(mSurfaceView.getVisibility());
             }
             mListener.surfaceCreated();
+
+            if (!mRanCallbacks && mPrevSurfaceDataNeedsDestroy == null) {
+                runCallbacks();
+            }
+
             mNeedsOnSurfaceDestroyed = true;
         }
 
@@ -282,6 +371,7 @@
                 Surface surface, boolean canBeUsedWithSurfaceControl, int width, int height) {
             if (mMarkedForDestroy) return;
             mListener.surfaceChanged(surface, canBeUsedWithSurfaceControl, width, height);
+            mNumSurfaceViewSwapsUntilVisible = 2;
         }
 
         @Override
@@ -293,7 +383,8 @@
         }
 
         private void runCallbacks() {
-            assert mCreated || mMarkedForDestroy;
+            mRanCallbacks = true;
+            if (mModeCallbacks.isEmpty()) return;
             // PostTask to avoid possible reentrancy problems with embedder code.
             PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
                 ArrayList<ValueCallback<Boolean>> clone =
@@ -304,6 +395,13 @@
                 }
             });
         }
+
+        private void runCallbackOnNextSurfaceData() {
+            if (mNextSurfaceDataNeedsRunCallback != null) {
+                mNextSurfaceDataNeedsRunCallback.runCallbacks();
+                mNextSurfaceDataNeedsRunCallback = null;
+            }
+        }
     }
 
     // Adapter for SurfaceHoolder.Callback.
@@ -400,7 +498,7 @@
         assert callback != null;
         if (mRequested != null && mRequested.getMode() != mode) {
             if (mRequested != mCurrent) {
-                mRequested.markForDestroy(mMarkedForDestroySurfaces, false /* hasNextSurface */);
+                mRequested.markForDestroy(false /* hasNextSurface */);
                 mRequested.destroy();
             }
             mRequested = null;
@@ -408,7 +506,8 @@
 
         if (mRequested == null) {
             SurfaceEventListenerImpl listener = new SurfaceEventListenerImpl();
-            mRequested = new SurfaceData(mode, this, listener, mBackgroundColor);
+            mRequested = new SurfaceData(
+                    mode, this, listener, mBackgroundColor, this::evictCachedSurface);
             listener.setRequestData(mRequested);
         }
         assert mRequested.getMode() == mode;
@@ -462,14 +561,15 @@
      */
     public void destroy() {
         if (mRequested != null) {
-            mRequested.markForDestroy(mMarkedForDestroySurfaces, false /* hasNextSurface */);
+            mRequested.markForDestroy(false /* hasNextSurface */);
+            mRequested.destroy();
             if (mCurrent != null && mCurrent != mRequested) {
-                mCurrent.markForDestroy(mMarkedForDestroySurfaces, false /* hasNextSurface */);
+                mCurrent.markForDestroy(false /* hasNextSurface */);
+                mCurrent.destroy();
             }
         }
         mRequested = null;
         mCurrent = null;
-        runPendingSurfaceDestroy();
 
         mWindowAndroid = null;
         ContentViewRenderViewJni.get().destroy(mNativeContentViewRenderView);
@@ -494,17 +594,14 @@
     }
 
     @CalledByNative
-    private void didSwapFrame() {
+    private boolean didSwapFrame() {
         assert mCurrent != null;
-        mCurrent.didSwapFrame();
-        runPendingSurfaceDestroy();
+        return mCurrent.didSwapFrame();
     }
 
-    private void runPendingSurfaceDestroy() {
-        for (SurfaceData surface : mMarkedForDestroySurfaces) {
-            surface.destroy();
-        }
-        mMarkedForDestroySurfaces.clear();
+    private void evictCachedSurface() {
+        if (mNativeContentViewRenderView == 0) return;
+        ContentViewRenderViewJni.get().evictCachedSurface(mNativeContentViewRenderView);
     }
 
     public long getNativeHandle() {
@@ -522,6 +619,7 @@
         void surfaceDestroyed(long nativeContentViewRenderView, boolean cacheBackBuffer);
         void surfaceChanged(long nativeContentViewRenderView, boolean canBeUsedWithSurfaceControl,
                 int width, int height, Surface surface);
+        void evictCachedSurface(long nativeContentViewRenderView);
         ResourceManager getResourceManager(long nativeContentViewRenderView);
     }
 }